virtual与析构函数引起我的悲剧
场景: 定义一个接口类, 不同子类实现接口. 实现多态. 看下面代码
// virtual与析构函数引起我的悲剧
// File.h
class MyInterface
{
public:
virtual int Fun1() = 0;
virtual int Fun2() = 0;
virtual int Fun3() = 0;
};
///////////////////////////////////////////
class MySubClass : public MyInterface
{
public:
MySubClass();
virtual ~MySubClass();
virtual int Fun1();
virtual int Fun2();
virtual int Fun3();
private:
unsigned char* m_pData;
};
//////////////////////////////////////////////////////////////
// File.cpp
MySubClass::MySubClass()
{
m_pData = new char[20];
}
MySubClass::~MySubClass()
{
delete [] m_pData;
}
int MySubClass::Fun1()
{
return 1;
}
int MySubClass::Fun2()
{
return 2;
}
int MySubClass::Fun3()
{
return 3;
}
///////////////////////////////////////////////////////////////////////////////// Use.cpp
#include "File.h"
MyInterface* pMyInterface = new MySubClass;
pMyInterface->Fun1();
delete pMyInterface;
悲剧发生: 内存泄露了! 这么就简单的一段代码, 内存泄露了? 该delete的我都delete
排查: 调试发现MySubClass的析构函数没有调用.
原因: delete pMyInterface; 调用的是MyInterface类的编译器给的析构函数(因为我在MyInterface定义中没有给出析构函数). 不是多态吗? 应该先调用MySubClass的析构函数吗?
很明显, 编译器给的MyInterface的析构函数没有virtual修饰, 所以delete pMyInterface并没有多态.
更悲剧的事情: 如果我是在上面代码上发现这个问题, 找原因可能一下子就可以找到了, 可是不是啊, 是在另外一个工程中发生了内存泄露,
找啊找啊找啊, 用了我两天的时间啊........ 鬼才知道是这个基础的原因引起,
总结教训:
排查原因要分主次
1. 先从最基础的原因入手, 从最常见的错误原因入手. 例如上面说的原因; 例如new了, 没delete;
2. 在确保了不是1引起的, 再去看程序的逻辑流程. 例如虽然new了也对应delete了, 但是由于一些跳转引起了并没有调用delete.
3. 在排查程序的逻辑流程的时候, 单元测试要做好. 通常程序有好几个或者几十个单元模块组成, 这么多个模块扯在一起, 是模块实现问题还是模块调用问题? 谁知道.
如果你确保了某个单元模块的实现是绝对没问题的, 可以迅速排出很多原因的.
正确代码是:
// virtual与析构函数引起我的悲剧
// File.h
class MyInterface
{
public:
MyInterface(){}
virtual MyInterface(){} // ----------------------就加多这两句-------------------------
virtual int Fun1() = 0;
virtual int Fun2() = 0;
virtual int Fun3() = 0;
};
class MySubClass : public MyInterface
{
public:
MySubClass();
virtual ~MySubClass();
virtual int Fun1();
virtual int Fun2();
virtual int Fun3();
private:
unsigned char* m_pData;
};
// File.cpp
MySubClass::MySubClass()
{
m_pData = new char[20];
}
MySubClass::~MySubClass()
{
delete [] m_pData;
}
int MySubClass::Fun1()
{
return 1;
}
int MySubClass::Fun2()
{
return 2;
}
int MySubClass::Fun3()
{
return 3;
}
// Use.cpp
#include "File.h"
MyInterface* pMyInterface = new MySubClass;
pMyInterface->Fun1();
delete pMyInterface;
本文探讨了在C++中使用虚拟析构函数的重要性。通过一个具体的案例分析,展示了当基类的析构函数未声明为虚函数时,派生类的资源无法正确释放,从而导致内存泄漏的问题。文章还提供了正确的代码实现方式。
2143

被折叠的 条评论
为什么被折叠?



