构造函数负责创建并初始化对象的内部环境,包括分配内存、创建内部对象和打开相关的外部资源等等。析构函数则负责相关的释放操作。
1、对于C++语言来说,由于构造函数产生异常时不会调用对应的析构函数,那么在构造函数里发生异常前的代码所创建的资源就不能被析构函数释放。
#include <iostream> #include <string> using namespace std; class TestObj { public: TestObj(); ~TestObj(); }; TestObj::TestObj() { } TestObj::~TestObj() { cout << "Destroy TestObj!" << endl; } class TestException { private: TestObj* obj; char* words; public: TestException(); ~TestException(); }; TestException::TestException() { obj = new TestObj(); //exception occur words = new char[1024*10000000000000]; } TestException::~TestException() { delete obj; delete[] words; } int main() { TestException te; }
words分配内存失败了,但此前的obj已经从堆分配成功,在抛出exception“terminate called after throwing an instance of 'std::bad_alloc'”后,obj并没有被释放掉,而且因为没有对异常进行处理,程序结束运行。
2、在异常发生时,释放obj。
#include <iostream> #include <string> #include <utility> using namespace std; class TestObj { public: TestObj(); ~TestObj(); }; TestObj::TestObj() { } TestObj::~TestObj() { cout << "Destroy TestObj!" << endl; } class TestException { private: TestObj* obj; char* words; public: TestException(); ~TestException(); }; TestException::TestException() { obj = new TestObj(); try { words = new char[1024*100000000000]; } catch(std::exception e) { delete obj; throw e; } } TestException::~TestException() {
delete obj; delete[] words; } int main() { try { TestException te; } catch(std::exception e) { cout<< e.what() << endl; } }
3、使用auto_ptr(智能指针)来代替指针,C++退出作用域时会自动释放变量,obj的释放操作交由auto_ptr来代劳,这样只需要在上一层处理异常即可。
#include <iostream> #include <string> #include <utility> using namespace std; class TestObj { public: TestObj(); ~TestObj(); }; TestObj::TestObj() { } TestObj::~TestObj() { cout << "Destroy TestObj!" << endl; } class TestException { private: std::auto_ptr<TestObj> obj; char* words; public: TestException(); ~TestException(); }; TestException::TestException() { std::auto_ptr<TestObj> _obj(new TestObj()); obj = _obj; words = new char[1024*100000000000]; } TestException::~TestException() { delete[] words; } int main() { try { TestException te; } catch(std::exception e) { cout << e.what() << endl; } }
4、析构函数不能抛出异常,如若发生异常时,需把异常完全封装在析构函数内部,决不让异常抛出函数之外。
1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。
2)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。