Can I forward construction in the body of a constructor?

Viewed 220

Let's consider that during the execution of the constructor of a class S, it appears that S could be constructed using another constructor. One solution could be to make a placement new at this to reuse the storage:

struct S{
    unsigned int j; //no const neither reference non static members
    S(unsigned int i){/*...*/}
    S(int i){
       if (i>=0) {
         new (this) S(static_cast<unsigned int>(i));
         return;}
       /*...*/
       }
    };
 int i=10;
 S x{i};//is it UB?

Storage reuse is defined in [basic.life]. I don't know how to read this section when the storage is (re)used during constructor execution.

2 Answers

The standard is completely underspecified in this case, and I cannot find a relevant CWG issue.

In itself, your placement new is not UB. After all, you have storage without an object, so you can directly construct an object in it. As you correctly said, the lifetime of the first object hasn't started yet.

But now the problem is: What happens to the original object? Because normally, a constructor is only called on storage without an object and the end of constructor marks the start of the lifetime of the object. But now there is already another object. Is the new object destroyed? Does it have no effect?

The standard is missing a paragraph in [class.cdtor] that says what should happen if a new object is created in the storage of an object under construction and destruction.

You can even construct even weirder code:

struct X {
  X *object;
  int var;
  X() : object(new (this) X(4)), var(5) {} // ?!?
  X(int x) : var(x) {}
} x;

is it UB?

No it is not. [basic.life]/5 says:

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.

Emphasis on the part relevant to your class which has a trivial destructor. About the specific new (this) T; form, I found no exception to this rule in [class.cdtor] nor [class.dtor].

Related