Let’s say we have a code like this:
class A {
public:
virtual int vFunc() { ... }
....
}
class B : public A {
public:
int vFunc() override { ... }
...
}
class C {
public:
C() {
m_b = new B();
m_b->vFunc();
}
....
private:
...
B * m_b;
...
}
Since class C
‘s m_b
is assigned before any first use, this should practically be equivalent to assigning m_b
through initializer-list i.e. C() : m_b(new B())
(apart from initialization order).
Now, right after new B()
, I call B::vFunc()
. For some reason, GCC’s optimizer de-virtualize this call to A::vFunc()
— not B::vFunc()
, A::vFunc()
[1]. This doesn’t make any sense, and the only explanation I can give is that the code above somehow contains an undefined behavior, giving GCC leeways to optimize however it wants. If I use the initializer list instead, GCC doesn’t seem to de-virtualize (I disassembled in GDB).
Am I right, or is there any other explanation as to why GCC wrongly de-virtualize something like this?
[1] This is GCC 13.2 as shipped by Ubuntu 24.04. Unfortunately, I cannot get GCC to exhibit the same behavior with a minimal reproduce code.
2