- 通过用户去调用工厂方法创建对象,然后delet是不安全的---见条款13
- 如何修改factory函数避免调用的错误?---见条款18
-
删除指向派生类的基类对象指针可能带来内存泄漏。
- 删除指向派生类的基类对象,只会调用基类析构函数。
#include <iostream> using namespace std; class Base{ public: ~Base() {cout<<"~B"<<endl;} }; class Derived:public Base{ public: ~Derived() {cout<<"~D"<<endl;} }; int main (){ Base *b = new Derived; //注意这里 delete b; }
查看打印日志:
~B
可见删除指向派生类的基类对象,代表delete只删除了父类,并没有删除子类的相关内存,会产生内存泄漏。所以在多态的使用过程中,delete(指向父类的子类对象)需要格外注意是否会没有释放子类或者父类。
- 正常的调用:delete指向派生类的派生类对象
#include <iostream> using namespace std; class Base{ public: ~Base() {cout<<"~B"<<endl;} }; class Derived:public Base{ public: ~Derived() {cout<<"~D"<<endl;} }; int main (){ Derived *d = new Derived; //注意这里 delete d; }
子类指向子类指针,查看打印日志:
~D
~B
可以得知,delete子类的析构顺序:是先释放子类,在释放父类。
这是我们期望的结果,所以没啥问题。。。
- 通过基类析构函数加上virtual避免delete Base类带来内存泄漏
对于第一种情况,如何去规避呢? 需要将父类的析构函数定义为virtual
#include <iostream> using namespace std; class Base{ public: virtual ~Base() {cout<<"~B"<<endl;} }; class Derived:public Base{ public: ~Derived() {cout<<"~D"<<endl;} }; int main (){ Base *d = new Derived; //注意这里 delete d; }
打印结果:
~D
~B
参考:C++ virtual 析构函数_zion--6135的博客-CSDN博客
- 总结:如果一个类要用作继承的基类,那么他的析构函数应该声明为virtual
-
如果这个类不希望被当作基类使用,析构函数不该加上virtual
- 如果一个类没有virtual函数,代表这个类不希望被用作Base class,如果这样还是把析构函数用作virtual,这会带来坏处:因为每一个类中的只要有virtual函数,那么就会产生一个vptr(虚函数指针),这会带来额外的内存开销。
-
为抽象类定义一个pure virtual析构函数
- pure virtual函数导致不能实例化此类。
- 当希望拥有一个抽象类,但没有虚函数,就可以将析构函数定义为pure virtual,本质上还是基类析构函数加上virtual避免内存泄漏,只不过在一个没有虚函数的抽象类上,这个虚析构函数是 pure virtual析构函数。如下的 virtual ~AWOV() = 0;
#include <iostream> using namespace std; //abstract class class AWOV { public: virtual ~AWOV() = 0; }; AWOV::~AWOV(){ printf("AAA\n"); } //derived class class derived :public AWOV { public: ~derived(){ printf("BBB\n"); } }; int main (){ AWOV* p = new derived; delete p; printf("CCC\n"); }
打印结果:
BBB
AAA
CCC