一、C++ 内存泄露
C++本身没有GC机制,所以需要开发人员做好内存管理。一般情况,C++内存泄露主要原因为:
1. 在构造和析构函数中,没有匹配new和delete;
2. 没有将基类的析构函数定义为virtual(如果没有定义virtual的话,析构函数只清理自己的成员)
二、虚析构函数的作用
下面根据三个场景来说明基类中virtual虚析构函数的作用
1. 派生类指针指向派生类对象
#include <iostream>
using namespace std;
class Father{
public:
Father(){
cout << "Father()" << endl;
}
virtual ~Father(){
cout << "~Father()" << endl;
}
};
class Son : public Father{
public:
Son(){
cout << "Son()" << endl;
}
~Son(){
cout << "~Son()" << endl;
}
};
int main(int argc, char** argv){
Son *obj = new Son;
delete obj;
}
当派生类指针指向派生类的时候,运行结果如下:
释放指针obj的时候,调用顺序:基类构造函数 -> 派生类构造函数 -> 派生类析构函数 -> 基类析构函数。
2.基类指针指向派生类(基类用virtual,虚析构函数)
#include <iostream>
using namespace std;
class Father{
public:
Father(){
cout << "Father()" << endl;
}
virtual ~Father(){
cout << "~Father()" << endl;
}
};
class Son : public Father{
public:
Son(){
cout << "Son()" << endl;
}
~Son(){
cout << "~Son()" << endl;
}
};
int main(int argc, char** argv){
Father *obj = new Son;
delete obj;
}
用virtual析构函数的基类指向派生类,运行结果如下(与派生类指向派生类相同):
释放指针obj的时候,调用顺序:基类构造函数 -> 派生类构造函数 -> 派生类析构函数 -> 基类析构函数。
3.基类指针指向派生类(无virtual)
#include <iostream>
using namespace std;
class Father{
public:
Father(){
cout << "Father()" << endl;
}
~Father(){
cout << "~Father()" << endl;
}
};
class Son : public Father{
public:
Son(){
cout << "Son()" << endl;
}
~Son(){
cout << "~Son()" << endl;
}
};
int main(int argc, char** argv){
Father *obj = new Son;
delete obj;
}
基类的析构函数没有virtual,用基类指针指向派生类的时候,运行结果如下:
释放指针obj的时候,调用顺序:基类构造函数 -> 派生类构造函数 -> 基类析构函数。
这种情况只释放了基类的资源,没有调用派生类的析构函数,对obj进行delete的时候,派生类的资源没有被删除,造成内存泄露。
三、基类virtual析构函数的作用
将一个基类指针指向派生类对象,如果基类的析构函数没有定义成virtual虚函数,编译器的静态绑定,在删除基类指针的时候,只会调用基类的析构函数,也就意味着只释放了基类的资源,派生类的成员没有被释放,因此导致内存没有被完全释放,即内存泄漏。
为了防止此类内存泄露,需要将基类的析构函数定义为virtual,从而可以在删除基类指针的时候,一并释放派生类的成员。