(making community-wiki as incorporating dyp's comment re 3.8/7 is very significant; while my earlier analysis was correct I would have said much the same things about code that was broken, having overlooked 3.8/7 myself)
Const *q,*p = new Const(1);
new (p) Const(2);
The new(p) Const(2);
line overwrites the object that had been constructed with Const(1)
.
memcpy (&q, &p, sizeof p);
This is equivalent to q = p;
.
cout << q->i;
This accesses the q->i
member, which will be 2
.
The somewhat noteworthy things are:
std::memcpy
is an ugly way to assign p
to q
... it is legal though under 3.9/3:
For any trivially copyable type T
, if two pointers to T
point to distinct T
objects obj1
and obj2
, where neither obj1
nor obj2
is a base-class subobject, if the underlying bytes (1.7) making up obj1
are copied into obj2
, obj2
shall subsequently hold the same value as obj1
. [ Example:
T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p contains
// the same value as the corresponding subobject in *t2p
The overwriting of the old Const(1)
object with Const(2)
is allowed as long as the program doesn't depend on side effects of the former's destructor, which it doesn't.
(as dyp noted in comments below) ongoing access to the Const(2)
object using p
is illegal under 3.8/7's third point:
pointer that pointed to the original object [...] 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 ...
- using
q
- rather than p
- to access i
is presumably necessary to avoid compiler optimisations based on presumed knowledge of i
.
As for your commentary:
Note that after construction of second Const
, p
doesn't semantically (intentionally?) points to new object, and the first is gone, so it is usable "as a void*
".
Given you placement-new an object at the address contained in p
, p
most certainly does point to the newly created object, and very intentionally, but it can't be used to manipulate that object under 3.8/7 as above.
Given you seem to have a notion of "semantically pointing" that's not defined in C++ the truth of that part of the statement's in your own mind.
'after construction of second Const
, p
...is usable "as a void*
' makes no sense... it's not more usable as anything than it was beforehand.
But the second object is constructed at the exact same address, so the bit pattern of p
represents the address of the new object.
Of course, but your comments show you think "bit pattern" is somehow distinct from the value of the pointer as applies to assignment with =
, which is not true.
new (p) Const(2)
erase the old object stored at p
, so the pointer is not valid anymore, except as a pointer to storage (void*
).
"erase" is a strange term for it... overwrites would be more meaningful. As dyp noted and explained above, 3.8/7 says you shouldn't "manipulate" the object p
points to after the placement new, but the value and type of the pointer are unaffected by the placmeent new. Much as you can call f(void*)
with a pointer to any type, the placement-new
doesn't need to know or care about the type of the p
expression.
After either p->~Const()
or memset (p, 0, sizeof *p)
it is clear that p
does not point to a valid object, so p
can only be used as pointer to storage (void*
or char*
), for example to reconstruct another object. At that point p->get0()
is not allowed.
Most of that's true, if by "p
can only be used" you mean the value of p
at that time rather than the pointer itself (which can be of course also be assigned to). And you're trying to be a little too clever with the void*
/ char*
thing - p
remains a Const*
, even if it's only used by placement new which doesn't care about the pointee type.
"I want to recover the value of p
as a Const*
."
The value of p
was not changed after it was first initialised. placement-new
uses the value - it does not modify it. There's nothing to recover as nothing was lost. That said, dyp's highlighted the need not to use p
to manipulate the object, so while the value wasn't lost it's not directly usable as wanted either.