指向子类的指针上的删除是否会调用基类析构函数?
-
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
在上面的例子中,每个delete和delete[]都是需要的。在我没有使用它的地方不需要删除(或者确实能够使用)。
auto_ptr
, unique_ptr
和 shared_ptr
ETC...非常适合使生命周期管理变得更加容易:
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
其他提示
当你对new分配的指针调用delete时,将调用所指向对象的析构函数。
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
.
您应该在 B 的析构函数中自己删除 A。
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”)。我只有像“ A类”这样的声明;编译器对此感到满意,让我称之为“删除”。
不。指针将被删除。您应该在 B 的析构函数中显式调用 A 的删除。
仅当调用 A 类对象的 delete 时,才会调用该对象的析构函数。确保在 B 类的析构函数中删除该指针。
有关在对象上调用 delete 时发生的情况的更多信息,请参阅:http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9
不,它不会呼叫A类的驱动器,您应该明确称其为(如Poweroy告诉),删除行'delete 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 但没有指向 new 的内存,则会出现堆损坏。)
auto_ptr<A> a;
...
b->a.reset(new A);
这样你就没有 a 作为指针,而是一个 auto_ptr<> (shared_ptr<> 也可以,或者其他智能指针),并且当 b 是时它会自动删除。
这两种方法都效果很好,我都用过。