2011-10-10 248 views
5

下面的示例会留下可能的内存泄漏,因为析构函数不会在其构造函数运行期间处理异常的对象运行。我在哪里处理这个内存泄漏?在构造函数中捕获异常

#include <exception> 

class MyClass { 

public: 
     MyClass() 
     { 
      c = new char[5]; 
      throw std::runtime_error("test"); 
     } 

     ~MyClass() 
     { 
      delete[] c; 
     } 

private: 
    char *c; 
}; 

int main() 
{ 
    try 
    { 
     MyClass Obj; 

    } 
    catch (std::runtime_error) 
    { 

    } 
} 

回答

5

您最好使用RAII,在这种情况下,智能指针是具体的。

或者,您可以使用Two Phased Construction策略。

你总是可以在构造函数主体中使用封闭的try-catch块,并显式调用删除所有你动态分配的资源,但想到你有动态分配的资源数量的情况下,显式地保持跟踪变得非常混乱在您需要在catch中取消分配的每个资源中,在这种情况下,RAII为您提供了最佳解决方案,因为这样每个资源都会隐式地处理自己的重新分配,并且不需要具有跟踪每个资源的开销。

boost::scoped_ptrstd::tr1::scoped_ptr适合这种情况,而不是任何原始指针。

+2

什么要求这个downvote? RAII是解决这个问题的最好方式,如果有人说不是这样的话。如果您觉得对Downvote负责任,那么有责任对我们解释为什么?如果你不能&只是*感觉*这是错误的,那么你没有足够的资格进行downvoting,让其他人这样做。 –

+0

是基于C++ 11相关内容的解决方案吗? – user103214

+0

不,这是C++ 03。 –

6

在构造函数中捕获异常,整理(释放你的内存),然后抛出异常而没有内存泄漏。

+0

当我在构造函数中抛出内存泄漏的异常时,析构函数从未被调用过。这有什么理由吗? – user103214

+1

@ user974191:对象构造不完整,直到构造函数的结束括号。析构函数仅针对已完成的对象调用。如果构造函数没有完全执行,则该对象不存在,因此不会调用析构函数。 –

1

你能赶上在构造函数体中的例外,做你的需要清理,然后再次抛出与throw;

也就是说,异常和内存手工处理的例外时没有很好地一起去。使用自动管理c成员的内存的对象(例如std::string,std::vector<char>,std::unique_ptr<char[]>等)将会更好。如果你正在写一个像上面这样的类,那么你只需要明确地管理内存,其目的正是为了照顾内存。

4

一种方法是throw条件异常在构造函数的开头,然后分配内存。

MyClass() 
    { 
    if(<condition>) 
     throw std::runtime_error("test"); 
    c = new char[<SIZE>]; 
    } 

另一种方法是使用特殊的语法try-catch()封闭的构造:

MyClass() 
    try { 
    c = new char[5]; 
    throw std::runtime_error("test");; 
    } 
    catch(std::runtime_error e) { 
    delete[] c; 
    } 

Demo