Другие ответы дают правильные замечания о неопределенном поведении, но я удивлен, что никто не упомянул, как эта программа должна быть исправлена.
Деструктор
Sub
требует, чтобы вызывался здесь вручную, но он должен вызываться до размещения нового , а не во время уничтожения:
class C
{
Sub sub;
public:
C() {
(&sub)->~Sub();
new (&sub) Sub(10);
}
};
В текущем коде вы создаете экземпляр C
, который по умолчанию создает экземпляр Sub
, а затем немедленно помещает новости в другой экземпляр Sub
поверх старого без вызова его деструктор. В конце основного c
вызывается деструктор, который явно вызывает деструктор sub
, затем деструктор sub
снова вызывается для уже разрушенного объекта. Это не только неопределенное поведение, если выделен конструктор Sub
по умолчанию, у вас также будет утечка памяти.
В исправленном коде sub
создается по умолчанию, уничтожается вручную, создается путем размещения нового, затем неявно уничтожается, когда c
выпадает из области видимости в конце main.
Таким образом, ответ таков: компилятор не знает, что деструктор нужно вызывать, когда вы воссоздаете объект по тому же адресу, потому что для размещения new не требуется объект в качестве первого параметра он принимает void*
. У него нет возможности определить, указывает ли этот указатель на существующий объект, поэтому вы должны вызвать деструктор вручную.