如何在try-catch块中释放内存?

时间:2010-06-15 19:31:49

标签: c++ try-catch delete-operator

我希望有一个简单的问题 - 当异常发生时,如何在try块中分配一个空闲内存?请考虑以下代码:

try
 {
  char *heap = new char [50];
        //let exception occur here
  delete[] heap;
 }
 catch (...)
 {
  cout << "Error, leaving function now";
  //delete[] heap; doesn't work of course, heap is unknown to compiler
  return 1;
 }

如何在分配堆之后释放内存并在调用delete[] heap之前发生异常?在这些try .. catch块中是否有规则不在堆上分配内存?

9 个答案:

答案 0 :(得分:34)

研究 RAII习语资源获取是初始化)!参见例如Wikipedia article on RAII

RAII只是一般的想法。它被用于例如在C ++标准库的std::unique_ptrstd::shared_ptr模板类中。


对RAII习语的非常简短的解释:

基本上,它是在其他一些语言中找到的try..finally块的C ++版本。 RAII习语可以说更灵活。

它的工作原理如下:

  • 您在资源周围编写了一个包装类(例如内存)。析构函数负责释放资源。

  • 您可以在作用域中创建包装类的实例作为本地(自动)变量。一旦程序执行离开该范围,将调用该对象的析构函数,从而释放资源(例如内存)。

重要的是 如何退出范围无关紧要。即使抛出异常,仍然会退出作用域,并且仍然会调用包装器对象的析构函数。


非常粗略的例子:

// BEWARE: this is NOT a good implementation at all, but is supposed to
// give you a general idea of how RAII is supposed to work:
template <typename T>
class wrapper_around
{
  public:
    wrapper_around(T value)
        : _value(value)
    { }
    T operator *()
    {
        return _value;
    }
    virtual ~wrapper_around()
    {
        delete _value;  // <-- NOTE: this is incorrect in this particular case;
                        // if T is an array type, delete[] ought to be used
    }
  private:
    T _value;
};
// ...

{
    wrapper_around<char*> heap( new char[50] );
    // ... do something ...

    // no matter how the { } scope in which heap is defined is exited,
    // if heap has a destructor, it will get called when the scope is left.
    // Therefore, delegate the responsibility of managing your allocated
    // memory to the `wrapper_around` template class.
    // there are already existing implementations that are much better
    // than the above, e.g. `std::unique_ptr` and `std::shared_ptr`!
}

答案 1 :(得分:9)

好先生Java程序员:

try
{
    // Exception safe dynamic allocation of a block of memory.
    std::vector<char>  heap(50);

    // DO STUFF

    // Note in C++ we use stack based objects and their constructor/destructor
    // TO give a deterministic cleanup, even in the presence of exceptions.
    //
    // Look up RAII (bad name for a fantastic concept).
}
catch (...)
{
    cout << "Error, leaving function now";
    return 1;  // Though why you want to return when you have not fixed the exception is
               // slightly strange. Did you want to rethrow?
}

答案 2 :(得分:8)

一般答案是使用RAII。

但是,可以通过将变量移出try {}范围来解决它:

char * heap = NULL;
try {
  heap = new char [50];
  ... stuff ...
} catch (...) {
  if (heap) {
    delete[] heap;
    heap = NULL;
  }
  ... however you want to handle the exception: rethrow, return, etc ...
}

请注意,我不建议将此作为一种良好的做法 - 但更多的是降低&amp;只有在你真正了解风险且仍愿意承担风险时才能使用。就个人而言,我会使用RAII。

和平

答案 3 :(得分:6)

new之前移动try,以便指针仍然在范围内,或使用智能指针,如shared_ptrunique_ptr(在紧要关头, auto_ptr,但它有问题)将在退出时为您清理。例外是智能指针很重要的一个重要原因。

答案 4 :(得分:3)

正确的答案是RAII和shared_ptr,如上所述,但只是为了完整:在你的例子中,你可以替换

char *heap = new char [50];

char *stack = static_cast<char*>( alloca(50) );

alloca几乎与malloc完全相同,除了它在堆栈而不是堆上的内存,因此无论你如何退出(抛出或现在),内存都将被回收,并且不需要删除或释放。

答案 5 :(得分:1)

我必须同意所有那些说过RAII的人,但是,我会使用Boost的shared_array而不是auto_ptr。自动指针调用delete而不是'delete []',这将导致数组泄漏。

答案 6 :(得分:0)

最简单的方法是在try块之前声明变量,然后在块中进行初始化。

答案 7 :(得分:0)

是的 - 如果你正在考虑简单性 - 你的try块外面的指针是解决方案。

此致

答案 8 :(得分:-4)

同意RAII和智能指针的答案。

但是,如果你坚持,你可以这样做:

try { dangerous operations } 
catch { cleanup; throw; }