Consider the following example:
#include <iostream>
struct A {
int i;
A(int i)
{
this->i = i;
}
A &operator=(const A &a) = delete;
A(const A &a) = delete;
};
int main()
{
A a(1);
new(&a) A(5);
//a = A(7); // not allowed since = is deleted in A
std::cout << a.i << std::endl;
}
This is a simple example using the placement new operator. Since the copy constructor and assignment operator of struct A
have been deleted (for whatever reason), it is not possible to change the object the variable A a
holds, except for passing its address to the placement new operator.
Reasons for this might include that struct A
holds large arrays (e.g. 100M entries) which would have to be copied in the assignment operator and the copy constructor.
The first part of the question revolves around the "legality" of this approach. I found this stackoverflow question, the accepted answer of which says
this is perfectly legal. And useless, because you cannot use var [
A a
in this case] to refer to the state of the [object] you stored within it after the placement new. Any such access is undefined behavior. […] under no circumstance may you ever refer to var after you placement new'd over it.
Why would that be the case? I have seen several other examples for the placement new operator, which are always similar to
A a(1);
A *b = new(&a) A(2);
// Now use *b instead of a
From my understanding it should not matter whether A a
or A *b
is used to access the object since the placement new replaces the object at the address of A a
which of course is A a
. That is, I would expect that always b == &a
. Maybe the answer was not clear enough and this limitation is due to the const-ness of the class member.
Here is another example with the same idea, however this time struct A
is embedded into another object:
#include <iostream>
struct A {
int *p;
A(int i)
{
p = new int(i);
}
~A()
{
delete p;
}
A &operator=(const A &a) = delete;
A(const A &a) = delete;
};
struct B {
A a;
B(int i) : a(i)
{
}
void set(int i)
{
a.~A(); // Destroy the old object
new(&a) A(i);
}
};
int main()
{
B b(1);
b.set(2);
std::cout << *(b.a.i) << std::endl;
// This should print 2 and there should be no memory leaks
}
The question is basically the same with the same reasoning. Is it valid to placement-new into the address &a
?