Могу ли я отправить конструкцию в тело конструктора?

Предположим, что при выполнении конструктора класса S представляется, что S можно построить с использованием другого конструктора. Одним из решений может быть сделать размещения нового в this для повторного хранения:

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?

Повторное использование хранилища определено в [basic.life]. Я не знаю, как читать этот раздел, когда хранилище (re) используется во время выполнения конструктора.

Ответы

Ответ 1

В этом случае стандарт полностью не указан, и я не могу найти соответствующую проблему CWG.

Само по себе ваше размещение новое не UB. В конце концов, у вас есть хранилище без объекта, поэтому вы можете напрямую построить в нем объект. Как вы правильно сказали, время жизни первого объекта еще не началось.

Но теперь проблема: что происходит с исходным объектом? Поскольку, как правило, конструктор вызывается только при хранении без объекта, а конец конструктора обозначает начало жизненного цикла объекта. Но теперь есть еще один объект. Уничтожен новый объект? Это не имеет никакого эффекта?

В стандарте отсутствует абзац в [class.cdtor], в котором говорится, что должно произойти, если новый объект создается при хранении объекта, находящегося в стадии строительства и уничтожения.

Вы даже можете построить еще более странный код:

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

Ответ 2

это UB?

Нет. [basic.life]/5 говорит:

Программа может завершить время жизни любого объекта за счет повторного использования хранилища, которое занимает объект, или путем явного вызова деструктора для объекта типа класса с нетривиальным деструктором. Для объекта типа класса с нетривиальным деструктором программа не требует прямого вызова деструктора до того, как хранилище, которое объект занимает, повторно используется или освобождается; однако, если нет явного вызова деструктора или если выражение удаления не используется для освобождения хранилища, деструктор не должен быть неявно вызван, и любая программа, зависящая от побочных эффектов, создаваемых деструктором, имеет неопределенное поведение.

Акцент на части, относящейся к вашему классу, который имеет тривиальный деструктор. О конкретном new (this) T; form, я не нашел исключения для этого правила в [class.cdtor] или [class.dtor].