Делает ли уничтожение и воссоздание объекта все указатели на этот объект недействительными?

Это продолжение к этот вопрос. Предположим, у меня есть этот код:

class Class {
public virtual method()
{
this->~Class();
new( this ) Class();
}
};

Class* object = new Class();
object->method();
delete object;

которая является упрощенной версией того, что этот ответ предлагает.

Теперь однажды деструктор вызывается изнутри method() время жизни объекта заканчивается и указатель на переменную object в вызывающем коде становится недействительным. Затем новый объект создается в том же месте.

Делает ли это указатель на объект в вызове снова действительным?

9

Решение

Это явно подтверждено в 3.8: 7:

3.8 Время жизни объекта [basic.life]

7 — Если после того, как время жизни объекта закончилось […], в месте хранения, которое занимал исходный объект, создается новый объект, указатель, который указывает на исходный объект […], может использоваться для манипулировать новым объектом, если: (различные требования, которые удовлетворяются в этом случае)

Пример приведен ниже:

struct C {
int i;
void f();
const C& operator=( const C& );
};
const C& C::operator=( const C& other) {
if ( this != &other ) {
this->~C(); // lifetime of *this ends
new (this) C(other); // new object of type C created
f(); // well-defined
}
return *this;
}
8

Другие решения

Собственно, это нормально. Однако без экстремальный забота, это станет отвратительным куском UB. Например, любые производные классы, вызывающие этот метод, не получат нужный тип заново, или что произойдет, если Class() бросает исключение. Кроме того, это ничего не дает.

Это не совсем UB, но это огромная куча дерьма и неудач, и его следует сжечь на месте.

4

object указатель не становится недействительным в любое время (при условии, что ваш деструктор не вызывает delete this). Ваш объект никогда не был освобожден, он только вызвал его деструктор, то есть он очистил свое внутреннее состояние (что касается реализации, обратите внимание, что стандарт строго определяет, что объект уничтожается после вызова деструктора). Поскольку вы использовали размещение new для создания экземпляра нового объекта с точно таким же адресом, это технически нормально.

Точный сценарий описан в разделе 3.8.7 стандарта C ++:

Если после окончания срока службы объекта и до хранения
занятый объект используется повторно или освобождается, новый объект
созданный в месте хранения, которое занимал исходный объект,
указатель, указывающий на исходный объект, ссылка, на которую ссылается
к исходному объекту, или имя исходного объекта будет
автоматически ссылаться на новый объект и, по истечении времени жизни
новый объект запущен, может использоваться для манипулирования новым объектом […]

Тем не менее, это интересно только как учебный код, как производственный код, это ужасно 🙂

4

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

В некоторых случаях люди считают, что адрес не меняется, но в некоторых случаях он меняется, например, при использовании С realloc(), Но это другая история.

0

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

0

Создание нового объекта в месте уничтоженного не делает указатели снова действительными. Они могут указывать на действительный новый объект, но не на тот объект, на который вы изначально ссылались.

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

Это будет особенно сложная ситуация для отладки.

-2
По вопросам рекламы [email protected]