Как удалить объект, построенный с помощью размещения нового оператора? - PullRequest
18 голосов
/ 18 июля 2011
char * buf = new char[sizeof(T)];
new (buf) T;
T * t = (T *)buf;
//code...
//here I should destruct *t but as it is argument of template and can be
//instantiated via basic types as well (say int) so such code 
/*t->~T();*/
//is incorrect (maybe correct? Strange, but it works on VS 2005 for basic types.)
//and this code 
/*delete t;*/ 
//crashes the program.
delete [] buf;

Итак, как правильно уничтожить t?

PS Приведенный выше код предназначен только для описания моей проблемы и не имеет реальных отношений с кодом, который я собираюсь написать.Поэтому, пожалуйста, не давайте ответы типа (Зачем использовать размещение new вместо отсутствия размещения? Или что-то подобное)

Ответы [ 4 ]

25 голосов
/ 18 июля 2011

... создается также через базовые типы (скажем, int), поэтому такой код
t->~T(); неверен
...

Неправильно.Этот код допустим и корректен в коде шаблона, даже если T может быть примитивным типом.

Стандарт C ++: 5.4.2

5.2.4 Вызов псевдо-деструктора [expr.pseudo]

  1. Использование псевдо-деструктора-имени после оператора . или стрелки -> представляет деструктор для не-класс типа, названный по имени типа.Результат должен использоваться только в качестве операнда для вызова функции operator (), а результат такого вызова имеет тип void.Единственным эффектом является оценка выражения постфикса перед точкой или стрелкой.
  2. Левая часть оператора точки должна быть скалярного типа.Левая часть оператора стрелки должна указывать на скалярный тип.Этот скалярный тип является типом объекта.Тип, обозначаемый псевдо-деструктором-name, должен совпадать с типом объекта.Кроме того, два имени типа в псевдодеструкторе имени вида ::opt nested-name-specifieropt type-name :: ˜ type-name должны обозначать один и тот же скалярный тип.Безусловные версии cv типа объекта и типа, обозначенного псевдодеструктором-name, должны быть одного типа.
11 голосов
/ 18 июля 2011

Сначала вы уничтожаете объект, напрямую вызывая деструктор:

t->~T();

Затем вы уничтожаете память, вызывая delete[] на указателе, возвращенном из new[]:

delete []buf;
7 голосов
/ 18 июля 2011

вызов деструктора

T * t = (T *)buf;
t->~T();

затем освободите память с помощью delete[] buf. Явный вызов деструкторов - это именно то, как это делается для объектов, созданных с размещением new.

3 голосов
/ 18 июля 2011

Память фактически была выделена с помощью char*; , который вы правильно освобождаете, используя delete[] buf. Вам просто нужно вызвать деструктор t->~T() в этом случае для t. Не надо delete t;.

Размещение new в этом случае используется только для построения объекта, а не для выделения памяти.

...