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

Kra*_*Kra 24 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;
 }
Run Code Online (Sandbox Code Playgroud)

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

sta*_*ica 34

研究RAII习语(资源获取是初始化)!参见例如关于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`!
}
Run Code Online (Sandbox Code Playgroud)

  • @Kra:我会建议恰恰相反.您越早习惯可用库越好.另请注意,如果您没有经验,则很容易在实现中出错,并且很可能很难在问题所在的地方进行调试.如果您使用经过测试的库,您将能够专注于您的特定代码问题.之后,一旦您获得更多经验,您就可以实现自己的实现,或尝试了解库中的实现以及每个决策的基本原理. (2认同)

Mar*_*ork 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?
}
Run Code Online (Sandbox Code Playgroud)

  • @Kra:你有什么理由想要从异常转换为错误处理的返回值吗? (2认同)

Mor*_*hai 9

一般的答案是使用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 ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,我不建议将此作为一种良好的做法 - 但只有在您真正了解风险且仍愿意接受风险的情况下才能使用它们.就个人而言,我会使用RAII.

和平

  • 我想也许你的意思是RAII.我不认为让音乐行业参与将有助于异常安全:) (3认同)
  • RAII:资源获取是初始化.RIAA是一个不同的更邪恶的实体.:) (2认同)
  • `if(heap)delete [] heap;`是反模式.在NULL指针上使用`delete []`是完全安全的,什么都不做. (2认同)
  • 你忘记在 `try` 块中调用 `delete[] heap`。这就是为什么 RAII 模式比使用 `try/catch` 手动执行此操作更安全的原因。很容易搞砸。 (2认同)

Kat*_*ory 6

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

  • 在这种情况下,auto_ptr <>是完美的(如果智能指针是解决方案).但是像动态容器这样的其他方法呢? (2认同)
  • @John Dibling:auto_ptr在这种情况下会导致未定义的行为,因为它使用`delete`而不是`delete []`,如A. Levy所说(我之前暗示过). (2认同)