Your code causes undefined behavior.
Not just "undefined if A is used as a base class and this, that or the other". Actually undefined, always. return *this
is already UB, because this
is not guaranteed to refer to the new object.
Specifically, consider 3.8/7:
If, after the lifetime of an object
has ended and before the storage which
the object occupied is reused or
released, a new object is created at
the storage location which the
original object occupied, a pointer
that pointed to the original object, a
reference that referred to the
original object, or the name of the
original object will automatically
refer to the new object and, once the
lifetime of the new object has
started, can be used to manipulate the
new object, if:
...
— the type of the original object is
not const-qualified, and, if a class
type, does not contain any non-static
data member whose type is
const-qualified or a reference type,
Now, "after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied" is exactly what you are doing.
Your object is of class type, and it does contain a non-static data member whose type is const-qualified. Therefore, after your assignment operator has run, pointers, references and names referring to the old object are not guaranteed to refer to the new object and to be usable to manipulate it.
As a concrete example of what might go wrong, consider:
A x(1);
B y(2);
std::cout << x.c << "
";
x = y;
std::cout << x.c << "
";
Expect this output?
1
2
Wrong! It's plausible you might get that output, but the reason const members are an exception to the rule stated in 3.8/7, is so that the compiler can treat x.c
as the const object that it claims to be. In other words, the compiler is allowed to treat this code as if it was:
A x(1);
B y(2);
int tmp = x.c
std::cout << tmp << "
";
x = y;
std::cout << tmp << "
";
Because (informally) const objects do not change their values. The potential value of this guarantee when optimizing code involving const objects should be obvious. For there to be any way to modify x.c
without invoking UB, this guarantee would have to be removed. So, as long as the standard writers have done their job without errors, there is no way to do what you want.
[*] In fact I have my doubts about using this
as the argument to placement new - possibly you should have copied it to a void*
first, and used that. But I'm not bothered whether that specifically is UB, since it wouldn't save the function as a whole.