123456789101112131415161718192021222324252627282930313233343536 |
- C++ 虚析构函数的使用
- ===============================
- 不熟悉 C++ 的程序员会遇到一个问题,什么时候需要用虚析构函数? `When to use virtual destructors? <https://stackoverflow.com/questions/461203/when-to-use-virtual-destructors>`__ 解答了这个问题。
- 简单地说,就是如果需要通过基类指针析构对象的话,就需要虚析构函数,否则只有基类的析构函数会被调用,导致派生类中的使用的资源不会被释放。
- 那么什么时候会用到基类指针呢?通常是在使用多态类的时候。这就是为什么通常有虚函数的类需要有虚析构函数。但是在非多态类中,如果程序员要用基类指针调虚构函数的话,同样会有内存泄漏的问题,因此同样需要虚析构函数。例如::
- #include <vector>
-
- class Base
- {
- public:
- virtual ~Base() {}
- };
-
- class Derive: public Base
- {
- std::vector<int> v;
- public:
- Derive(): v(4, 0) {}
- };
-
- int main()
- {
- Base *p = new Derive;
- delete p;
- }
- 如果 Base 的析构函数不是虚函数,就会导致 Derive 类中的 vector 发生内存泄漏,使用 address sanitizer 可以证实这点。当然了,ASAN 会报一个 new-delete-type-mismatch 错误,表明调用了不正确的析构函数,设置 ``ASAN_OPTIONS=new_delete_type_mismatch=0`` 运行程序,就会报出内存泄漏。
- 不过,对于非多态类,程序员一般不会通过基类指针释放一个对象,因此不需要定义析构函数为虚函数。
- 此外,Stack Overflow 中有一个回答很有意思,如果使用 ``shared_ptr<Base>(new Derive)`` 的话,那么共享指针释放资源的时候,调用的是派生类的析构函数。通过查看 ``shared_ptr`` 的实现,可以发现 ``shared_ptr<_Tp>(_Yp *p)`` 实际上是一个函数模板,通过反汇编也可以看出这点。这个函数模板使得编译器可以检查类的派生关系,并使得产生的共享指针对象中能保存其中裸指针的实际类型信息。
|