4

is this a bug in VS 2013 compiler?
The following code produces different result in debug and release.
In debug the result is as expected, but in release it is "A"

#include <cstdio>

struct A
{
    virtual void* getClass() { return A::ID; };
    static void ID(){};
};

struct B : public A
{
    virtual void* getClass() { return B::ID; };
    static void ID(){};
};

struct C : public A
{
    virtual void* getClass() { return C::ID; };
    static void ID(){};
};


int main(int argc, char *argv[])
{
    A* d = new C;

    if (d->getClass() == A::ID)
    {
        printf("A");
    }
    else if (d->getClass() == B::ID)
    {
        printf("B");
    }
    else if (d->getClass() == C::ID)
    {
        printf("C");
    }

}
kamerunka
  • 106
  • 5
  • 1
    Hum... that's not even supposed to compile, you can't implicitly cast function pointers to `void*`. – Mat May 02 '15 at 03:05
  • any pointer should be casted to void*, some additional information, if I change ID in each class to: static char* ID(){ return "CLASS"; }; it seems to be OK, so it seems that the functions with same implementation are considered as the same function, but isn't that standart violation? – kamerunka May 02 '15 at 03:11
  • 1
    Please see [Can I convert a pointer-to-member-function to a void*?](https://isocpp.org/wiki/faq/pointers-to-members#cant-cvt-memfnptr-to-voidptr) – Shafik Yaghmour May 02 '15 at 03:12
  • 1
    the function is static, it is not a pointer to member – kamerunka May 02 '15 at 03:15
  • @kamerunka: doesn't matter. In standard C++ that implicit conversion is illegal. See the link posted by Shafik, the next item talks about plain functions. – Mat May 02 '15 at 03:16
  • @LightnessRacesinOrbit I don't think this is really a duplicate, that question only addresses half the issues. Part of this question is the non-conformant conversion, which is not part of that duplicate. – Shafik Yaghmour May 02 '15 at 03:27
  • I would reopen it myself but I was literally going to post my answer when you closed it. So that might seem like a conflict. – Shafik Yaghmour May 02 '15 at 03:28
  • You've explained why you think it's not a duplicate, so don't worry about conflict of interest. Though I do still disagree. – Lightness Races in Orbit May 02 '15 at 03:29

1 Answers1

1

It's due to compiler optimizations.

It appears that whether the compiler should perform this kind of optimization is debatable Do distinct functions have distinct addresses? .

typeid

A more conventional way is to use typeid to verify the runtime types. Note you dereference the pointer to get the type of the derived class.

if (typeid(*d) == typeid(A))
{
    printf("A");
}
else if (typeid(*d) == typeid(B))
{
    printf("B");
}
else if (typeid(*d) == typeid(C))
{
    printf("C");
}

Disable Optimization

However, because /OPT:ICF can merge identical data or functions, it can change the function names that appear in stack traces.

You can use /OPT:NOICF in release to prevent the behavior.


Also, you can see that actually implementing the functions differently causes it to work as you expect.

Example Code

#include <string>

struct A
{
    virtual std::string getClass() { return A::ID(); }
    static std::string ID(){ return "A"; }
};

struct B : public A
{
    virtual std::string getClass() { return B::ID(); }
    static std::string ID(){ return "B"; }
};

struct C : public A
{
    virtual std::string getClass() { return C::ID(); }
    static std::string ID(){ return "C"; }
};

int main(int argc, char *argv[])
{
    A* d = new C;

    if (d->getClass() == A::ID())
    {
        printf("A");
    }
    else if (d->getClass() == B::ID())
    {
        printf("B");
    }
    else if (d->getClass() == C::ID())
    {
        printf("C");
    }
}
Community
  • 1
  • 1
James Adkison
  • 9,412
  • 2
  • 29
  • 43
  • yes, I figured that out, but isn't that a standard violation? – kamerunka May 02 '15 at 03:16
  • "_The static A::ID, B::ID, and C::ID functions generate the exact same code and therefore they can be represented by a single function"_ Ehm... no, I don't think so. I concede that [this is contentious](http://stackoverflow.com/q/26533740/560648). – Lightness Races in Orbit May 02 '15 at 03:18
  • See [Do distinct functions have distinct addresses?](http://stackoverflow.com/q/26533740/1708801) – Shafik Yaghmour May 02 '15 at 03:18
  • Actually function pointers are more about "where" than "what". So if they are stored at the same memory address, then they can equal to each other. I don't think standard requires functions are stored at distinct locations. – user3528438 May 02 '15 at 03:20
  • @LightnessRacesinOrbit That's a good link, thanks. – James Adkison May 02 '15 at 03:25