Могу ли я отправить конструкцию в тело конструктора?
Предположим, что при выполнении конструктора класса 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]
.