我有两个类Base和Derived。当我在main中只创建一个Derived对象并写入返回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)
答案 0 :(得分:1)
当我在main中只创建了一个Derived对象并且写了返回0时,我看到了,base的解构函数和派生的都被称为
是的,Derived对象包含Base类型的基类子对象。
基类子对象负责它自己的初始化和销毁。因此,您应该将基类对象状态的清理委托给基类析构函数。
类似地,您应该将基类对象的构造委托给基类构造函数:这是已经隐式发生,因此派生类构造函数会泄漏内存。
答案 1 :(得分:0)
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
提供了一个受保护的构造函数,允许它构造一个大小。
Base()
委托给那个构造函数。
Derived()
也可以。
Base
管理内存,Derived
只更改默认大小。
您不能使用C ++类继承,也不能让派生类构造函数调用基类构造函数,也不能让派生析构函数不调用基类析构函数。
答案 2 :(得分:0)
当你赋予一个对象生命时,该对象是由所谓的 costructor链构建的;这意味着如果你想给Derived类型的对象赋予生命,首先必须对Base类型的对象进行构造
每个costructor都必须初始化它所属的类中的成员,因此Base将初始化Base的成员,Derived的costructor将初始化Derived的成员。
同样,当您需要删除Derived对象时,类似的链开始,但方向相反,即从Derived类到Base类。
对象必须逐个拆卸:派生的descrutor必须只删除Derived类中引入的成员,而不是其他成员。相反,删除Base类的成员是Base的类析构函数的唯一责任。
因此,删除Derived的析构函数中的行,删除Base类引入的数组
delete[] arr;
并将其保留在Base类中。