Является ли `new (this) MyClass ();` неопределенным поведением после прямого вызова деструктора? - PullRequest
9 голосов
/ 03 июня 2011

В этот мой вопрос , @DeadMG говорит, что повторная инициализация класса с помощью указателя this является неопределенным поведением.Есть ли где-нибудь упоминание об этом в стандарте?

Пример:

#include <iostream>

class X{
  int _i;
public:  
  X() : _i(0) { std::cout << "X()\n"; }
  X(int i) : _i(i) { std::cout << "X(int)\n"; }

  ~X(){ std::cout << "~X()\n"; }

  void foo(){
    this->~X();
    new (this) X(5);
  }

  void print_i(){
    std::cout << _i << "\n";
  }
};

int main(){
  X x;
  x.foo();
  // mock random stack noise
  int noise[20];
  x.print_i();
}

Пример вывода на Ideone (я знаю, что UB также может быть "на вид правильным поведением").
Обратите внимание, что я не вызывал деструктор вне класса, чтобы не получить доступ к объекту, время жизни которого закончилось.Также обратите внимание, что @DeadMG говорит, что прямой вызов деструктора в порядке, если он вызывается один раз для каждого конструктора.

Ответы [ 2 ]

8 голосов
/ 03 июня 2011

Это было бы хорошо, если бы это не конфликтовало с разматыванием стека.

Вы уничтожаете объект, а затем восстанавливаете его с помощью указателя.Это то, что вы сделали бы, если бы вам нужно было создать и уничтожить массив объектов, у которых нет конструктора по умолчанию.

Проблема в том, что это небезопасно для исключений.Что если вызов конструктора вызывает исключение и стек разматывается, а деструктор вызывается во второй раз?

{
   X x;
   x.foo(); // here ~X succeeds, then construction fails
} //then the destructor is invoked for the second time.

Этот аспект определенно будет неопределенным поведением.

0 голосов
/ 03 июня 2011

Кроме ответа @ sharptooth.Мне просто интересно еще 2 случая.По крайней мере, о них стоит упомянуть.

(1) Если foo() был вызван с использованием указателя на кучу, которая была выделена с помощью malloc().Конструктор называется , а не .Может ли это быть безопасно?

(2) Что если производный класс вызывает foo().Будет ли это хорошее поведение?например,

struct Y : X {};  // especially when there is virtual ~X()
int main ()
{
  Y y;
  y.foo();
}
...