Marc Mutz wrote:
I'm in discussion with a lib vendor who uses placement new
to forward construction to another ctor, like this:
MyClass( ... ) {
new (this) MyClass( ... );
}
I asked them to use a private init() function instead, but
they claim: you might be correct that using placement new to forward
construction is not well defined in the general case. In
our case however it is, as the class only contains one
pimpl-pointer (no members that have a constructor
and no vtable). In this case it's perfectly valid to use
the construct we're using.
Please supply me with ammonition to make them reconsider
(or tell me they're right :/).
This is already in shaky grounds because the lifetime of a non-POD
before construction completes and before destruction begins is really
hard to reason about and there are lots of restrictions on what is well
defined and what isn't (see 3.8 and the sections it references for more
details). But if we ignore that and pick a simpler reason why this code
is illegal:
3.8/1 "The lifetime of an object of type T begins when ... if T is a
class type and the constructor invoked to create the object is
non-trivial (12.1), the constructor call has completed."
MyClass::MyClass(...)
{
new ((void*)this) MyClass(...); //1
} //2
So what happens here is that they are using placement new to create a
new object at the location pointed to by this //1. This creates a new
MyClass object, that's fine (totally ignoring the issues I talked about
above). The problem occurs when the MyClass ctor returns //2, the
constructor call has completed, which means *two* MyClass objects are
created at the same memory location, which is illegal since MyClass is
not a POD struct. Since there is no way to forward ctor calls in the
current standard, the only legal thing to do is call an init()
function.