从基类delete派生类不一定会导致内存泄露的,主要发生在,派生类没有动态分配内存的时候,这种情况是无需在派生类的析构函数里面做一个释放内存的动作的,而virtual析构函数就是为了保证派生类析构函数一定会调用,但是没有动态分配内存,其实都没有给出析构函数的必要了,更加不用做调用了:
#include <iostream> using namespace std; class tt {}; class dd : public tt { int i; public: virtual void xx(){} }; int main() { tt *p = new dd; delete p; cout << sizeof(tt) << sizeof (dd) << endl; }
这里tt比派生类小,tt在做继承结构的时候大小为0,独立存在的时候是1.而派生类是8,包括一个int,和一vptr。但是,直接delete基类的指针p,也是不会有内存泄露的,因为释放内存的步骤就是,先call基类的析构函数,这里没有做virtual 析构,所以遗漏了派生类的,之后就是释放内存,反正p指向了正确的内存,内存首尾都是有一个对应的cookie的,记录内存大小,自然之后分配的一个dd对象的内存是不会泄露部分的。
我们看看valgrind内存检测结果:
[root@localhost c_proj]# valgrind --leak-check=full ./a.out ==2723== Memcheck, a memory error detector ==2723== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. ==2723== Using Valgrind-3.6.0 and LibVEX; rerun with -h for copyright info ==2723== Command: ./a.out ==2723== 18 ==2723== ==2723== HEAP SUMMARY: ==2723== in use at exit: 0 bytes in 0 blocks ==2723== total heap usage: 1 allocs, 1 frees, 8 bytes allocated ==2723== ==2723== All heap blocks were freed -- no leaks are possible ==2723== ==2723== For counts of detected and suppressed errors, rerun with: -v ==2723== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 8)
明显没有内存泄露的。
再看一个有泄露的版本呵呵:
[root@localhost c_proj]# g++ -g derive.cc [root@localhost c_proj]# ./a.out 112 [root@localhost c_proj]# cat derive.cc #include <iostream> using namespace std; class tt { public: ~tt(){} }; class dd : public tt { char *p; int i; public: dd() { i = 100; p = new char; } virtual void xx(){} ~dd() { delete p; } }; int main() { tt *p = new dd; delete p; cout << sizeof(tt) << sizeof (dd) << endl; } [root@localhost c_proj]# valgrind --leak-check=full ./a.out ==2910== Memcheck, a memory error detector ==2910== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. ==2910== Using Valgrind-3.6.0 and LibVEX; rerun with -h for copyright info ==2910== Command: ./a.out ==2910== 112 ==2910== ==2910== HEAP SUMMARY: ==2910== in use at exit: 1 bytes in 1 blocks ==2910== total heap usage: 2 allocs, 1 frees, 13 bytes allocated ==2910== ==2910== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==2910== at 0x400737F: operator new(unsigned int) (vg_replace_malloc.c:255) ==2910== by 0x80488CD: dd::dd() (derive.cc:19) ==2910== by 0x80487B7: main (derive.cc:30) ==2910== ==2910== LEAK SUMMARY: ==2910== definitely lost: 1 bytes in 1 blocks ==2910== indirectly lost: 0 bytes in 0 blocks ==2910== possibly lost: 0 bytes in 0 blocks ==2910== still reachable: 0 bytes in 0 blocks ==2910== suppressed: 0 bytes in 0 blocks ==2910== ==2910== For counts of detected and suppressed errors, rerun with: -v ==2910== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 15 from 8) [root@localhost c_proj]#
所以简单修正一下就是了:
[root@localhost c_proj]# g++ -g derive.cc [root@localhost c_proj]# cat derive.cc #include <iostream> using namespace std; class tt { public: virtual ~tt(){} }; class dd : public tt { char *p; int i; public: dd() { i = 100; p = new char; } virtual void xx(){} ~dd() { delete p; } }; int main() { tt *p = new dd; delete p; cout << sizeof(tt) << sizeof (dd) << endl; } [root@localhost c_proj]# valgrind --leak-check=full ./a.out ==2921== Memcheck, a memory error detector ==2921== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. ==2921== Using Valgrind-3.6.0 and LibVEX; rerun with -h for copyright info ==2921== Command: ./a.out ==2921== 412 ==2921== ==2921== HEAP SUMMARY: ==2921== in use at exit: 0 bytes in 0 blocks ==2921== total heap usage: 2 allocs, 2 frees, 13 bytes allocated ==2921== ==2921== All heap blocks were freed -- no leaks are possible ==2921== ==2921== For counts of detected and suppressed errors, rerun with: -v ==2921== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 8) [root@localhost c_proj]#
所以虚析构函数还是需要的。