Как удалить элемент в деструкторе ?

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

12 ответов


короткий ответ:: нет.

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

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

удачи.


зависит от того, что вы подразумеваете под "удалить". Если они не находятся в смарт-указателе и явно не удаляются, то они не удаляются. Члены, которые являются только частью класса:

class Bar {
//...
private: 
  Foo foo;
};

не удаляются деструктором (потому что они не были динамически выделены), они просто уничтожаются. Они "живут" внутри класса, поэтому, как только он уничтожен, он исчезнет.

Если вы ищете долю "владения" между двумя местоположениями, то вы хотите динамически выделено shared_ptr:

#include <memory>
class Bar {
// ...
private:
  std::tr1::shared_ptr<Foo> foo;
};

если элемент содержится в стоимостью (не указателем или ссылкой), то вы не можете предотвратить его удаление, и вы не должны этого хотеть.

Если вы хотите удалить его в другом месте, а затем сделать его содержащимся указателем или ссылкой.

class House
{
  Door door; //contained by value, will be destroyed when the House is
}

class House
{
  Door& door; //contained by reference, will not be destroyed when the House is
}

код в деструкторе предназначен только для удаления динамически выделяемых элементов. Уничтожение членов не является необязательным, вы можете управлять только освобождением того, что вы явно выделили раньше (с оператором new).

то, что вы хотите сделать, можно получить с помощью shared_ptr, в котором как ваш класс, так и внешний код используют указатель на один и тот же внешний объект. Таким образом, только тогда, когда все указатели на этот объект выйдут из области видимости, он будет удален. Но остерегайтесь не делать круговых ссылок, shared_ptr не имеет мудрости "сборщика мусора".

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


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

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

As на вопрос, не является ли это необоснованным, я думаю, что это не так, в общем, но вы должны дать понять (обычно в документации, так как C++ не имеет языковой поддержки для этого понятия), что такое объект, который принадлежит член в вопрос.


Я думаю, что в большинстве случаев вы напрашиваетесь на неприятности, если вы не уничтожите весь объект в том же действии. Похоже, ваш класс должен иметь метод очистки для этого члена, который вызывается в деструкторе. Если по какой-то причине член должен быть уничтожен раньше, метод может вернуться раньше.


прежде всего, это полностью неразумно?

Я бы не сказал, неразумно, возможно, сомнительно.

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

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


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


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


class Foo
{
public:
  Foo() {p = new int;}
 ~Foo(){}

private:
 int a;
 int *p;
};

этот класс имеет 2 члена данных: целое число a и указатель на целое число p. Когда вызывается деструктор, объект уничтожается, то есть вызываются деструкторы для всех его членов. Это происходит, даже если тело деструктора пусто. В случае примитивного типа, такого как целое число, вызов его деструктора просто означает, что занимаемая им память будет освобождена. Однако есть уловка, когда вы уничтожаете указатель: все, на что он указывает, не уничтожается по умолчанию. Для этого вы должны явно вызвать delete.

так, в нашем примере a будет уничтожен при вызове деструктора, и так будет p, но не все p указывает. Если вы хотите освободить память, к которой p очки, деструктор для Foo должен выглядеть так:


~Foo() {delete p};

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


Почему никто не упомянул слабые и сильные указатели?
Сильный указатель-это умный указатель, который действует нормально.
Слабый указатель-это умный указатель, который не может удалить себя, если все сильные указатели не выходят за рамки.
Сильный указатель указывает на владение, слабый указатель указывает на совместное использование.
Посмотреть импульс.shared_ptr и импульс.создание и Локи StrongPtr для реализации.
Также взгляните на RAII. Если бы ты знал рая, ты бы сам знал ответ на этот вопрос.


Это не является необоснованным, но следует позаботиться о том, чтобы очистка любых управляемых ресурсов обрабатывалась неявно.

(первый управляемый ресурс, о котором люди обычно беспокоятся, - это память, но все, что может протекать - память, дескрипторы файлов, указатели IDispatch - должно иметь код, который обрабатывает очистку неявно).

для управляемых ресурсов, совместно используемых несколькими объектами (почти наверняка, если" этот объект " должен иметь указатель на что-то, что очищается "этим объектом"), вам обычно нужен либо "указатель подсчета ссылок" для управления объектом, либо "слабый указатель", в зависимости от ваших требований к жизни.

для управляемых ресурсов, которые не являются общими (и в частности те, которые нужно уметь правильно управлять, когда исключения могут быть брошены), то auto_ptr или другой вариант может быть более подходящим.

эффективные книги Скотта Мейерса на C++ были разумной отправной точкой для изучение умных указателей, но на практике вы, вероятно, должны просто захватить проверенную библиотеку, как Boost и пусть кто-то другой беспокоится о получении неясных угловых случаев (например, что происходит, если конструктор выдает исключение?) право.


это возможно, но в основном, как сказал @dmckee, это проблема собственности. Если это так, вы можете пойти на переучет. т. е.

class A
{

RefObj* obj;
A()
{

obj = new RefObj;

}

~A()
{
 obj->ReleaseRef();
}
}


RefObj
{

int m_iRefCounter;
RefObj()
{
m_iRefCounter = 1;
}
AddRef()
{
m_iRefCounter++;
}
ReleaseRef()
{
m_iRefCounter--
if(m_iRefCounter == 0)
{
 delete this;
}
}
}

}