Вызывает ли удаление указателя на подкласс деструктор базового класса?
-
21-08-2019 - |
Вопрос
у меня есть class A
который использует выделение памяти в куче для одного из своих полей.Класс A создается и сохраняется как поле указателя в другом классе (class B
.
Когда я закончил работу с объектом класса B, я вызываю delete
, который, как я полагаю, вызывает деструктор...Но вызывает ли это также деструктор класса A?
Редактировать:
Из ответов я понял следующее (пожалуйста, отредактируйте, если это неправильно):
delete
экземпляра B вызывает B::~B();- который вызывает
A::~A();
A::~A
должен явноdelete
все переменные-члены объекта A, выделенные в куче;- Наконец, блок памяти, хранящий указанный экземпляр класса B, возвращается в кучу - когда новый был использован, он сначала выделил блок памяти в куче, затем вызвал конструкторы для его инициализации, теперь после того, как все деструкторы были вызваны для финализации объекта, блок, в котором находился объект, возвращается в кучу.
Решение
Деструктор A запустится, когда его время жизни закончится.Если вы хотите, чтобы его память была освобождена и запустился деструктор, вам придется удалить его, если он был выделен в куче.Если он был выделен в стеке, это происходит автоматически (т.когда оно выходит за рамки;см. RAII).Если это член класса (не указатель, а полноценный член), то это произойдет при уничтожении содержащего его объекта.
class A
{
char *someHeapMemory;
public:
A() : someHeapMemory(new char[1000]) {}
~A() { delete[] someHeapMemory; }
};
class B
{
A* APtr;
public:
B() : APtr(new A()) {}
~B() { delete APtr; }
};
class C
{
A Amember;
public:
C() : Amember() {}
~C() {} // A is freed / destructed automatically.
};
int main()
{
B* BPtr = new B();
delete BPtr; // Calls ~B() which calls ~A()
C *CPtr = new C();
delete CPtr;
B b;
C c;
} // b and c are freed/destructed automatically
В приведенном выше примере необходимы все операции удаления и удаления[].И удаление не требуется (или не может быть использовано) там, где я его не использовал.
auto_ptr
, unique_ptr
и shared_ptr
и т. д...отлично подходят для упрощения управления жизненным циклом:
class A
{
shared_array<char> someHeapMemory;
public:
A() : someHeapMemory(new char[1000]) {}
~A() { } // someHeapMemory is delete[]d automatically
};
class B
{
shared_ptr<A> APtr;
public:
B() : APtr(new A()) {}
~B() { } // APtr is deleted automatically
};
int main()
{
shared_ptr<B> BPtr = new B();
} // BPtr is deleted automatically
Другие советы
Когда вы вызываете delete для указателя, выделенного new, будет вызван деструктор объекта, на который указывает.
A * p = new A;
delete p; // A:~A() called for you on obkect pointed to by p
Он называется «деструктор», а не «деконструктор».
Внутри деструктора каждого класса вам необходимо удалить все остальные переменные-члены, выделенные с помощью new.
редактировать:Чтобы уточнить:
Скажи, что у тебя есть
struct A {}
class B {
A *a;
public:
B () : a (new A) {}
~B() { delete a; }
};
class C {
A *a;
public:
C () : a (new A) {}
};
int main () {
delete new B;
delete new C;
}
Выделение экземпляра B, а затем его удаление является чистым, потому что то, что B выделяет внутри, также будет удалено в деструкторе.
Но экземпляры класса C будут вызывать утечку памяти, поскольку он выделяет экземпляр класса A, который не освобождает (в данном случае у C даже нет деструктора).
Если у вас есть обычный указатель (A*
) то деструктор вызываться не будет (и память для A
экземпляр также не будет освобожден), если вы этого не сделаете delete
явно в B
деструктор.Если вы хотите автоматическое уничтожение, посмотрите на умные указатели, например auto_ptr
.
Вы должны удалить A самостоятельно в деструкторе B.
class B
{
public:
B()
{
p = new int[1024];
}
virtual ~B()
{
cout<<"B destructor"<<endl;
//p will not be deleted EVER unless you do it manually.
}
int *p;
};
class D : public B
{
public:
virtual ~D()
{
cout<<"D destructor"<<endl;
}
};
Когда вы это сделаете:
B *pD = new D();
delete pD;
Деструктор будет вызываться только в том случае, если ваш базовый класс имеет ключевое слово virtual.
Тогда, если у вас не было виртуального деструктора, будет вызываться только ~B().Но поскольку у вас есть виртуальный деструктор, сначала будет вызван ~D(), затем ~B().
Никакие члены B или D, выделенные в куче, не будут освобождены, если вы явно не удалите их.И их удаление также вызовет их деструктор.
Мне было интересно, почему не был вызван деструктор моего класса.Причина была в том, что я забыл включить определение этого класса (#include "class.h").У меня было только заявление, как «класс А»; И компилятор был доволен этим и позволил мне позвонить «Delete».
Нет.указатель будет удален.Вы должны явно вызвать удаление A в деструкторе B.
Деструктор объекта класса A будет вызываться только в том случае, если для этого объекта вызывается удаление.Обязательно удалите этот указатель в деструкторе класса B.
Дополнительную информацию о том, что происходит при вызове метода delete для объекта, см. в разделе:http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9
Нет, он не будет вызывать деструктор для класса А, вы должны назвать его явно (как сказал Poweroy), удалить линию «Удалить ptr;» В примере для сравнения ...
#include <iostream>
class A
{
public:
A(){};
~A();
};
A::~A()
{
std::cout << "Destructor of A" << std::endl;
}
class B
{
public:
B(){ptr = new A();};
~B();
private:
A* ptr;
};
B::~B()
{
delete ptr;
std::cout << "Destructor of B" << std::endl;
}
int main()
{
B* b = new B();
delete b;
return 0;
}
У вас есть что-то вроде
class B
{
A * a;
}
B * b = new B;
b->a = new A;
Если вы затем позвоните delete b;
, с a ничего не происходит, и у вас происходит утечка памяти.Пытаясь вспомнить delete b->a;
это не очень хорошее решение, но есть еще пара других.
B::~B() {delete a;}
Это деструктор для B, который удалит a.(Если a равно 0, удаление ничего не делает.Если a не равно 0, но не указывает на новую память, вы получите повреждение кучи.)
auto_ptr<A> a;
...
b->a.reset(new A);
Таким образом, у вас в качестве указателя будет не a, а auto_ptr<> (подойдет также иshared_ptr<> или другие интеллектуальные указатели), и он автоматически удаляется, когда есть b.
Любой из этих способов работает хорошо, и я использовал оба.