Подтвердить что ты не робот

Вызов деструктора, а затем конструктор (сброс объекта)

Я хочу reset объект. Могу ли я сделать это следующим образом?

anObject->~AnObject();
anObject = new(anObject) AnObject();
// edit: this is not allowed: anObject->AnObject();

Этот код, очевидно, является подмножеством типичного жизненного цикла объекта, выделенного при размещении new:

AnObject* anObject = malloc(sizeof(AnObject));
anObject = new (anObject) AnObject(); // My step 2.
// ...
anObject->~AnObject(); // My step 1.
free(anObject)
// EDIT: The fact I used malloc instead of new doesn't carry any meaning

Единственное, что изменилось, это порядок вызовов конструктора и деструктора.

Итак, почему в после часто задаваемых вопросов появляется угроза?

[11.9] Но могу ли я явным образом называть деструктор, если я выделил свой объект с новым?

Часто задаваемые вопросы: вы не можете, если объект не был выделено с размещением нового. Объекты созданные новым, должны быть удалены, что делает две вещи (помните их): звонки деструктор, затем освобождает память.

FQA: Перевод: удаление - это способ явно называть деструктор, но он также освобождает память. Ты можешь также вызвать деструктор без освобождение памяти. Это уродливое и бесполезно в большинстве случаев, но вы можете сделать что.

Деструктор/вызов конструктора, очевидно, является нормальным кодом на С++. Гарантии, используемые в коде, напрямую вытекают из размещения новых гарантий. Это ядро ​​стандартного, оно отличает твердую вещь. Как его можно назвать "грязным" и быть представленным как нечто ненадежное?

Считаете ли вы возможным, что внедрение новых и не-размещения новых отличается? Я думаю о какой-то больной возможности, что обычный новый может, например, поместить размер блока памяти, выделенного перед блоком, который, по-видимому, не будет делать в новом месте (поскольку он не выделяет никакой памяти). Это может привести к пробелу в некоторых проблемах... Возможна ли такая новая() реализация?

4b9b3361

Ответ 1

Не всасывайте троллей FQA. Как обычно, он ошибается.

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

"Регулярный" новый/удаление упрощает это, связывая выделение памяти и создание объекта вместе, а распределение стека упрощает его еще больше, делая оба для вас.

Однако, совершенно справедливо следующее:

int foo() {
    CBar bar;
    (&bar)->~CBar();
    new (&bar) CBar(42);
 }

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

Ответ 2

Почему бы не реализовать метод Clear(), который делает все, что делает код в теле деструктора? Затем деструктор просто вызывает Clear(), и вы вызываете Clear() непосредственно на объект в "reset it".

Другой вариант, если ваш класс правильно поддерживает назначение:

MyClass a;
...
a = MyClass();

Я использую этот шаблон для сброса экземпляров std:: stack, поскольку адаптер стека делает не обеспечивают четкой функции.

Ответ 3

Технически это плохая практика для вызова конструкторов или деструкторов явно.

Ключ delete в конечном итоге вызывает их, когда вы его используете. То же самое касается новых конструкторов.

Извините, но этот код заставляет меня хотеть вырвать мои волосы. Вы должны делать это так:

Выделить новый экземпляр объекта

AnObject* anObject = new AnObject();

Удалить экземпляр объекта

delete anObject;

НИКОГДА не выполняйте это:

anObject->~AnObject(); // My step 1.
free(anObject)

Если вы должны "reset" создать объект, создайте метод, который очистит все переменные экземпляра внутри, или то, что я рекомендую вам сделать, это удалить объект и выделить себе новый.

"Это ядро ​​языка?"

Это ничего не значит. Perl имеет около шести способов записи цикла for. Просто потому, что вы можете делать что-то на языке, потому что они поддерживаются, значит, вы должны их использовать. Черт, я мог бы написать весь свой код, используя операторы для switch, потому что "Core" языка поддерживает их. Не делает это хорошей идеей.

Почему вы используете malloc, когда вам явно не нужно. Malloc - это метод С.

Новые и Удалить - ваши друзья на С++

"Сброс" объекта

myObject.Reset();

Там вы идете. Таким образом, вы избавляетесь от ненужного выделения и освобождения памяти опасным образом. Напишите свой метод Reset(), чтобы очистить значение всех объектов внутри вашего класса.

Ответ 4

Вы не можете вызвать конструктор указанным вами способом. Вместо этого вы можете сделать это с помощью place-new (как и ваш код):

new (anObject) AnObject();

Этот код гарантированно будет хорошо определен, если ячейка памяти по-прежнему доступна - как и должно быть в вашем случае.

(Я удалил часть о том, является ли это дискуссионным кодом или нет - он четко определен. Полная остановка.)

Кстати, Брок прав: как реализация delete не фиксирована - это не то же самое, что вызвать деструктор, а затем free. Всегда парные вызовы new и delete, никогда не смешивайте их с другим: это undefined.

Ответ 5

Обратите внимание, что они не используются malloc и free, но operator new и operator delete. Кроме того, в отличие от вашего кода, используя новый, вы гарантируете безопасность исключений. Почти эквивалентный код будет следующим.

AnObject* anObject = ::operator new(sizeof(AnObject));
try
{
    anObject = new (anObject) AnObject();
}
catch (...)
{
    ::operator delete(anObject);
    throw;
}

anObject->~AnObject();
::operator delete(anObject)

reset, который вы предлагаете, действителен, но не является идиоматическим. Трудно получить право и, как правило, нахмуриться и обескураживать.

Ответ 6

Вы не можете вызвать такой конструктор, но нет ничего плохого в повторном использовании памяти и вызове нового места размещения, если вы не удаляете или не освобождаете (освобождаете) память. Я должен сказать, что перезапуск объекта вроде этого немного отрывочный. Я бы написал объект для явного сброса или написал метод подкачки и использовал его для reset it.

например.

anObject.swap( AnObject() ); // swap with "clean" object

Ответ 7

Если ваш объект имеет разумную семантику назначения (и правильный оператор =), то * anObject = AnObject() имеет больше смысла и легче понять.

Ответ 8

Лучше просто добавить что-то вроде метода Reset() к вашему объекту, а не играть с новым местом размещения.

Вы используете новую функцию размещения, которая предназначена для того, чтобы вы могли контролировать, где находится объект. Обычно это проблема только в том случае, если ваше оборудование имеет специальную память, такую ​​как флеш-чип. Если вы хотите поместить некоторые объекты в флеш-чип, вы можете использовать эту технику. Причина, по которой он позволяет вам явно вызвать деструктор, заключается в том, что вы теперь контролируете память, поэтому компилятор С++ не знает, как сделать часть освобождения удаления.

Он также не сохраняет много кода с помощью метода reset, вам нужно будет установить члены в их стартовые значения. malloc() не делает этого, поэтому вам все равно придется писать этот код в конструкторе. Просто создайте функцию, которая устанавливает ваши члены в начальные значения, называет ее Reset() вызовом ее из конструктора, а также из любого места, в котором вы нуждаетесь.