- Does the following code have a defined behavior ?
- If not, what part of the code is UB and what section(s) of the standard states it is UB ?
- If this code is UB, is there any [minor] change that can fix it ?
- If nothing can fix it, what other code scheme/pattern could be used to implement the same feature ?
class C
{
public:
virtual ~C() {}
virtual void switch_me() = 0;
};
class C1 : public C
{
public:
C1() : b(true) { std::cout << "C1\n"; }
~C1() { std::cout << "~C1\n"; }
private:
void switch_me();
bool b;
};
class C2 : public C
{
public:
C2() : i(1) { std::cout << "C2\n"; }
~C2() { std::cout << "~C2\n"; }
private:
void switch_me();
int i;
};
void C1::switch_me()
{
this->~C1(); // lifetime of *this ends here
std::cout << "blih\n"; // execute some code that does
// not attempt to access object
new(this) C2(); // create a C2 instance in-place
}
void C2::switch_me()
{
this->~C2(); // lifetime of *this ends here
std::cout << "blah\n"; // execute some code...
new(this) C1(); // create a C1 instance in-place
}
class Cnt
{
public:
Cnt() { new(&storage) C1(); }
~Cnt() { (*this)->~C(); }
C* operator->() { return reinterpret_cast<C*>(&storage); }
private:
char storage[std::max(sizeof(C1),sizeof(C2))];
};
int main()
{
Cnt c;
c->switch_me();
c->switch_me();
return 0;
}
You do not have Undefined Behavior regarding
switch_mefunction: you do not access object in any way after destruction, and next access happens on new object. You might have UB if you save pointer and reference toCobject returned vyoperator->and use it after call toswitch_meper 3.8/7:You do have UB in other place, namely, your storage. It has weaker alignment than object you want to place in it, and that can cause alignment issues. Use
alignaskeyword to specify desired alignment:If two alignment specifiers are applied to same declaration, larger is used.