logo资料库

几个内存泄漏的例子.doc

第1页 / 共7页
第2页 / 共7页
第3页 / 共7页
第4页 / 共7页
第5页 / 共7页
第6页 / 共7页
第7页 / 共7页
资料共7页,全文预览结束
几个内存泄漏的例子  new 和 delete 要成对使用  new 和 delete 要匹配 经常看到一些 C++方面的书籍中这样提及到内存泄漏问题,这样的说法的意思是比较明 白,但对于初学 C++程序员还是很难掌握,所以下面举几个反面的例子,希望对大家有帮助。 例一:错误处理流程中的 return 导致的内存泄漏 bool MyFun() { CMyObject* pObj = NULL; pObj = new CMyObject(); … if (…) return false; … if(…) return false; … if (pObj != NULL) delete pObj; return true; } 注意:红色字体部分的 return 之前没有释放 pObj,导致内存泄漏。 例二:exception 改变了程序的正常流程,导致内存泄漏 情况 1: HRESULT MyFun() { HRESULT hr = S_OK; try { CMyObject* pObj = NULL; pObj = new CMyObject(); … if (…) hr = E_FAIL; throw hr; { } … if(…) {
hr = E_FAIL; throw hr; } … if (pObj != NULL) delete pObj; } catch (HRESULT& eHr) { } return hr; } 情况 2: void OtherFun() // 可能是自己写的其他函数; // 也可能是其他人写的函数; // 也可能是系统的 API; { } … if(…) throw exception; … bool MyFun() { } CMyObject* pObj = NULL; pObj = new CMyObject(); … OtherFun(); … if (pObj != NULL) delete pObj; return true; 注意:上面的两种情况中的 throw 行为将导致程序的正常流程,一旦有 throw 的 动作发生,pObj 对象将不会被正确释放(delete)。 例三:忘记释放系统 API 创建的资源,导致内存泄露 bool CMyClass::MyFun() { HANDLE hHandle = CreateEvent(NULL,FALSE,TRUE,NULL); … if (…)
return false; … return true; } 注意:系统 API CreateEvent 创建的 HANDLE 对象,需要自己释放,否则会导致内 存泄漏。还有其他一些系统的 API 也是如此,如:CreateFile、CreateFileMapping 等等,所以我们在使用不熟悉的系统 API 时,一定要仔细阅读 MSDN。 例四:PostMessage 可能导致的内存泄漏 // 自定义的消息结构体 typedef struct tagMSG { int i; float f; }MSG; // 发送消息的函数 void MyFun() { } MSG* pMsg = new MSG; … PostMessage(m_hWnd, WM_MYEVENT, (WPARAM)pMsg, 0); // 接收消息的函数 afx_msg void OnMessage(WPARAM wParam, LPARAM lParam) { } MSG* pMsg = (MSG*)wParam; m_i = pMsg->i; m_f = pMsg->f; 注意:OnMessage 函数中忘记释放 pMsg,导致内存泄漏。 例五:函数返回 new 的对象而导致的内存泄漏 char* MyFun() { } char* p = new char[10]; … return p; 注意:调用 MyFun 程序的人可能不会注意到 MyFun 函数内部 new 出的对象,往往 会忽略对象 p 的释放。 例六:不好的类结构也会导致内存泄漏
// MyClass.h 文件 class MyClass { public: MyClass(); virtual ~MyClass(); BOOL Init(); BOOL UnInit(); private: char* m_pStr; } // MyClass.cpp 文件 MyClass::MyClass() : m_pStr(NULL) { } MyClass::~MyClass() { } BOOL MyClass::Init() { } m_pStr = new char[100]; … if (…) { } delete m_pStr; m_pStr = NULL; return FALSE; return TRUE; BOOL MyClass::UnInit() { } if (m_pStr != NULL) { } delete m_pStr; m_pStr = NULL; return TRUE;
注意:这个类在 Init()函数中 new 出类资源,需要调用相应的 UnInit()函数来释 放资源,但有些时候这个类需要给其他人使用,别人在使用时可能会忘记调用 UnInit()函数来释放资源,这样就造成了内存泄漏,为了防止这个问题发生,最 好在 MyClass::~MyClass()函数中也进行资源释放。如下写法: MyClass::~MyClass() { } UnInit(); 例七:容易忽视的深层次结构对象的内存泄漏 typedef struct MyStruct { } int i; BSTR bstr; void MyFun(OLECHAR * sz) { } MyStruct* pStru = new MyStruct; … pStru->bstr = SysAllocString(sz); … delete pStru; 注意:pStru 是个深层次结构的对象,在这个对象内部还有指针数据类型 bstr, 在释放 pStr 时,如果忘记了释放其内部的指针对象 bstr,也会导致内存泄漏。当 然这个例子比较简单,在我们实际编程时,深层次结构的对象要比这个复杂的多, 所以处理这些对象时需要格外小心。 例八:虚基类的析构函数可能导致的问题 /////////////////////////// // Base.h class Base { public: Base(); ~Base(); virtual void TestFun(); } // Base.cpp Base::Base() { }
Base::~Base() { } if (m_pStr != NULL) { } delete m_pStr; void Base::TestFun() { } ////////////////////////////// // MyClass.h class MyClass : public Base { public: MyClass(); ~MyClass(); virtual void TestFun(); protected: char* m_pStr; } // MyClass.cpp MyClass::MyClass() : m_pStr(NULL) { } MyClass::~MyClass() { } if (m_pStr != NULL) delete m_pStr; void MyClass::TestFun() { } m_pStr = new char[100]; /////////////////////////////
// Test.cpp int _tmain(int argc, _TCHAR* argv[]) { } Base* pClass = new CMyClass(); pClass->TestFun(); delete pClass; return 0; 注意:由于 Base 类的析构函数不是 virtual 类型,在_tmain 程序的用法中,将会 导致 CMyClass 的析构不会被调用,引起内存泄漏。 总结: 1、 C++编程中,内存泄漏是个比较烦人的问题,创建(new)对象的“入口”一般 只有一处,但需要释放(delete)对象的“出口”却很多,而且由于创建(new) 出来的对象的生存周期不固定,所以要完全避免内存泄漏是比较困难,需要我 们在编程时格外小心; 2、 养成良好的代码书写习惯,尽量在编写代码时解决内存泄漏问题; 3、 一旦程序中发生内存泄漏时,可以使用一些内存泄漏检查工具(如:Bound Check 等)来查找,这些工具可以帮助我们找出部分的内存泄漏的代码; 4、 有些内存泄漏的问题还需要我们手工查找,检查代码的逻辑也是查找内存泄漏 的一种有效手段。
分享到:
收藏