一、体现
0.代码:
class A;
class B
{public:
//构造函数在其它文件中
B(void);
~B(void)
{//如果A中还有堆开辟,那么会有内存泄漏
delete m_pA;
}A* m_pA;};
1.警告:
warning C4150: 删除指向不完整“Base”类型的指针;没有调用析构函数
2.解释
(1)Foreward declaration
使用前置声明(Foreward declaration)来声明class A,此时class A并没有完整的定义,表现为其后面的类只能申明其指针,或者引用,前置声明以后的类无法看到其类实体。一般使用一些智能指针的时候也会出现这个问题。
(2)Incomplete Type
由于A是Incomplete Type(不完整类型),编译器只是把A加入到符号表并标记A为一个class,编译器并不知道更多的信息,比如A的大小,有何成员函数等等。编译器也无法知道A所对应的析构函数(destructor),因此不会调用A的析构函数。
(3)delete
在调用delete来删除pA的时候,编译器可以知道pA所指的内存大小,因为内存分配器在内存块中保存了大小信息,可以正确释放A所占据的内存,此时的delete相当于free()。注意,但是如果是A在堆上开辟的内存(比如在构造函数中),那么这些内存将被保留。也就是说,如果A没有再在堆上开辟内存,那么也不会有内存泄漏。
三、后果
1.可能内存泄露
2.伴随的资源没有释放
四、解决方案
1.移进来A的头文件,去除A的Foreward declaration
2.如果考虑1可能带来的依赖,可将(delete pA)放到cpp中实现,在cpp中引入头文件,如果担心效率,可再放到nil的内联文件中
3.网上有人说:如果在其它地方调用了析构函数,那么可以用
delete (void *)pA;
删除内存。
猜想,这个可能只有Placement new的时候才有可能用到这种情况。
五、总结
视警告如错误,勿以恶小而为之 勿以善小而不为。