从基类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]#
所以虚析构函数还是需要的。