Как удалить объект, построенный с помощью нового оператора размещения?
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
?
P.S. Приведенный выше код предназначен только для описания моей проблемы и не имеет реальных отношений с кодом, который я собираюсь написать. Поэтому, пожалуйста, не отвечайте на такие вопросы, как (зачем использовать размещение new
вместо не размещения? Или что-то подобное)
Ответы
Ответ 1
... создается через базовые типы (скажем int
), поэтому такой код
t->~T();
неверно...
Неправильно. Этот код является законным и правильным в коде шаблона, даже если T
может быть примитивным типом.
Стандарт С++: 5.4.2
5.2.4 Вызов псевдодеструктора [expr.pseudo]
- Использование псевдо-деструктор-имя после того, как оператор точки
.
или стрелка ->
представляет деструктор типа non-class, названный именем типа. Результат должен использоваться только как операнд для вызова функции operator ()
, и результат такого вызова имеет тип void. Единственный эффект оценка постфиксного выражения перед точкой или стрелкой. - Левая часть оператора точки должна быть скалярного типа. Левый с правой стороны оператора стрелки должен быть указатель на скалярный тип. Этот скалярный тип является типом объекта. Тип, обозначенный псевдодвойство-имя должно быть таким же, как тип объекта. Кроме того, два имени типа в псевдоструктурированном имени форма
::opt nested-name-specifieropt type-name :: ˜ type-name
должна обозначают один и тот же скалярный тип. Cv-безусловные версии тип объекта и тип, обозначенный псевдо-деструктором-именем должны быть одного и того же типа.
Ответ 2
Сначала вы уничтожите объект, вызвав его деструктор:
t->~T();
Затем вы уничтожаете память, вызывая delete[]
по указателю, возвращенному из new[]
:
delete []buf;
Ответ 3
Вызвать деструктор
T * t = (T *)buf;
t->~T();
затем освободите память с помощью delete[] buf
. Вызов деструкторов явно - это точно, как это делается для объектов, созданных с помощью размещения new
.
Ответ 4
Память была фактически распределена с помощью char*
; , который вы правильно освобождаете, используя delete[] buf
. Вам просто нужно вызвать деструктор t->~T()
в этом случае для t
. Нет необходимости delete t;
.
Размещение new
в этом случае используется только для создания объекта, а не для выделения памяти.