我有两个类Base和Derive。当我在main中只创建了一个Derive对象并写返回0时,我看到基类的析构函数和派生类的析构函数都被调用。
因此我犯了一个错误。基类析构函数用于删除已经被派生类析构函数删除的内存。
所以,我不想调用基类的析构函数。我只想调用派生类析构函数,因为我只创建了派生类对象。
这是我的代码和我的错误。
#include <new>
#include <iostream>
using namespace std;
class Base {
public:
Base(){
size=4;
arr= new int[size];
for(int i=0;i<size;i++){
arr[i]=0;
}
}
~Base(){
cout<<"Base class destructor called"<<endl;
delete[] arr;
}
protected:
int *arr;
int size;
};
class Derived : public Base {
public:
Derived(){
size=5;
arr= new int[size];
for(int i=0;i<size;i++){
arr[i]=0;
}
}
~Derived(){
cout<<"Derived class destructor called"<<endl;
delete[] arr;
}
};
int main(){
Derived derivedObject;
return 0;
}
我的错误是,
Derived class destructor called
Base class destructor called
*** Error in `./exe': double free or corruption (fasttop): 0x0000000001f20c40 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f2d65d147e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f2d65d1d37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f2d65d2153c]
./exe[0x400c31]
./exe[0x400d31]
./exe[0x400afb]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f2d65cbd830]
./exe[0x4009f9]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:06 1183568 /home/burhan/Desktop/hw5-1/exe
00601000-00602000 r--p 00001000 08:06 1183568 /home/burhan/Desktop/hw5-1/exe
00602000-00603000 rw-p 00002000 08:06 1183568 /home/burhan/Desktop/hw5-1/exe
01f0f000-01f41000 rw-p 00000000 00:00 0 [heap]
7f2d60000000-7f2d60021000 rw-p 00000000 00:00 0
7f2d60021000-7f2d64000000 ---p 00000000 00:00 0
7f2d65994000-7f2d65a9c000 r-xp 00000000 08:06 2110523 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65a9c000-7f2d65c9b000 ---p 00108000 08:06 2110523 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65c9b000-7f2d65c9c000 r--p 00107000 08:06 2110523 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65c9c000-7f2d65c9d000 rw-p 00108000 08:06 2110523 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d65c9d000-7f2d65e5d000 r-xp 00000000 08:06 2110528 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d65e5d000-7f2d6605d000 ---p 001c0000 08:06 2110528 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d6605d000-7f2d66061000 r--p 001c0000 08:06 2110528 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d66061000-7f2d66063000 rw-p 001c4000 08:06 2110528 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d66063000-7f2d66067000 rw-p 00000000 00:00 0
7f2d66067000-7f2d6607d000 r-xp 00000000 08:06 2102075 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d6607d000-7f2d6627c000 ---p 00016000 08:06 2102075 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d6627c000-7f2d6627d000 rw-p 00015000 08:06 2102075 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d6627d000-7f2d663ef000 r-xp 00000000 08:06 1966485 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d663ef000-7f2d665ef000 ---p 00172000 08:06 1966485 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d665ef000-7f2d665f9000 r--p 00172000 08:06 1966485 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d665f9000-7f2d665fb000 rw-p 0017c000 08:06 1966485 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d665fb000-7f2d665ff000 rw-p 00000000 00:00 0
7f2d665ff000-7f2d66625000 r-xp 00000000 08:06 2110506 /lib/x86_64-linux-gnu/ld-2.23.so
7f2d667ff000-7f2d66804000 rw-p 00000000 00:00 0
7f2d66821000-7f2d66824000 rw-p 00000000 00:00 0
7f2d66824000-7f2d66825000 r--p 00025000 08:06 2110506 /lib/x86_64-linux-gnu/ld-2.23.so
7f2d66825000-7f2d66826000 rw-p 00026000 08:06 2110506 /lib/x86_64-linux-gnu/ld-2.23.so
7f2d66826000-7f2d66827000 rw-p 00000000 00:00 0
7ffe7cad2000-7ffe7caf3000 rw-p 00000000 00:00 0 [stack]
7ffe7cb04000-7ffe7cb06000 r--p 00000000 00:00 0 [vvar]
7ffe7cb06000-7ffe7cb08000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
当我在main中只创建了一个派生对象并写返回0时,我看到,基础和派生的解构函数都调用了
是的,派生对象包含Base类型的基类子对象。
基类子对象负责自己的初始化和销毁。因此,您应该将基类对象状态的清理委托给基类析构函数。
同样,您应该将基类对象的构造委托给基类构造函数:这已经隐式发生,因此您的派生类构造函数会泄漏内存。
class Base {
protected:
Base(std::size_t n) {
size=n;
arr= new int[size];
for(int i=0;i<size;i++){
arr[i]=0;
}
}
public:
Base():Base(4){}
~Base(){
std::cout<<"Base class destructor called\n";
delete[] arr;
}
protected:
int *arr;
int size;
};
class Derived : public Base {
public:
Derived():Base(5){}
~Derived(){
std::cout<<"Derived class destructor called\n";
}
};
你应该这样做。
Base
提供了一个受保护的构造函数,允许它构造-at-size。
Base()
委托给该构造函数。
Derive()
也是如此。
Base
管理内存,Derive
只是更改默认大小。
您不能使用C类继承而不让派生类构造函数调用基类构造函数,也不能让派生析构函数不调用基类析构函数。
当你给一个对象赋予生命时,这个对象是由所谓的构造函数链构建的;这意味着如果你想给一个派生类型的对象赋予生命,首先必须构造一个Base类型的对象。
每个构造函数都必须在它所属的类中初始化成员,所以Base将初始化Base的成员,Derive的构造函数将初始化Derive的成员。
同样,当你需要删除一个派生对象时,一个类似的链开始了,但方向相反,即从派生类到Base类。
对象必须一点一点地拆除:派生描述器必须只删除派生类中引入的成员,而不是其他成员。相反,删除Base类的成员是Base的类析构函数的独占责任。
因此,擦除Derive的析构函数中删除Base类引入的数组的行
delete[] arr;
并将其仅保留在基类中。