For the following base class B and derived D, virtual function something, union Space
#include <iostream>
using namespace std;
struct B {
void *address() { return this; }
virtual ~B() { cout << "~B at " << address() << endl; }
virtual void something() { cout << "B::something"; }
};
struct D: B {
~D() { cout << "~D at " << address() << endl; }
void something() override { cout << "D::something"; }
};
union Space {
B b;
Space(): b() {}
~Space() { b.~B(); }
};
If you have a value s of Space, G++ and Clang++ behave in the same way: If you do s.b.something(), B::something() will be called, not doing the dynamic binding on s.b, however, if you call (&s.b)->something() both will do the dynamic binding to what b really contains (either a B or D). The completion code is this:
union SpaceV2 {
B b;
SpaceV2(): b() {}
~SpaceV2() { (&b)->~B(); }
};
static_assert(sizeof(D) == sizeof(B), "");
static_assert(alignof(D) == alignof(B), "");
#include <new>
int main(int argc, const char *argv[]) {
{
Space s;
cout << "Destroying the old B: ";
s.b.~B();
new(&s.b) D;
cout << "\"D::something\" expected, but \"";
s.b.something();
cout << "\" happened\n";
auto &br = s.b;
cout << "\"D::something\" expected, and \"";
br.something();
cout << "\" happened\n";
cout << "Destruction of D expected:\n";
}
cout << "But did not happen!\n";
SpaceV2 sv2;
new(&sv2.b) D;
cout << "Destruction of D expected again:\n";
return 0;
}
When compile with -O2 optimization and I run the program, this is the output:
$./a.out
Destroying the old B: ~B at 0x7fff4f890628
"D::something" expected, but "B::something" happened
"D::something" expected, and "D::something" happened
Destruction of D expected:
~B at 0x7fff4f890628
But did not happen!
Destruction of D expected again:
~D at 0x7fff4f890608
~B at 0x7fff4f890608
What surprises me is that setting the dynamic type of s.b using placement new leads to a difference calling something on the very same l-value through its name or through its address. The first question is essential, but I have not been able to find an answer:
- Is doing placement new to a derived class, like
new(&s.b) Dundefined behavior according to the C++ standard? - If it is not undefined behavior, is this choice of not activating virtual dispatch through the l-value of the named member something specified in the standard or a choice in G++, Clang?
Thanks, my first question in S.O. ever.
Aucun commentaire:
Enregistrer un commentaire