4

有人可以描述处理以下情况的正确方法是什么:

wchar_t* buffer = new wchar_t[...];

if (!something)
{
    throw std::runtime_error("Whatever");
    // Now, at this point I'm leaking memory allocated for the 'buffer'.
}

// Perform actions.
delete[] buffer;

解决它的明显方法意味着:

if (!something)
{
    delete[] buffer;
    throw std::runtime_error("Whatever");
}

现在——还好吗?(我怀疑是这样,但谁知道:)


PS我确实意识到有一种更好的方法可以做到这一点-使用boost::scoped_array或简单地说std::wstring,它允许调用的析构函数释放分配的内存,只是好奇。

4

5 回答 5

8

你的洞察力是对的。图案

Acquire some resource
Do something
Release resource

根本上是错误的,因为Do something可能会引发异常并泄漏资源。此外,您必须记住释放资源,这是错误的肥沃来源。

正如您所指出的,正确的方法是始终使用析构函数释放资源的对象。这在 C++中称为RAII 。

这意味着例如。永远不要使用delete外部析构函数,或者永远不要依赖手动关闭文件句柄,永远不要手动解锁互斥锁等。了解智能指针,并尽可能使用它们。

请注意,某些语言(不是 C++)提供了一个finally关键字,它允许您执行一个指令块,而不管是否引发异常。C++ 使用 RAII,如果你编写了适当的析构函数,你永远不应该关心资源释放。

我有一个用于 C++0x 的小实用程序它允许在块退出时执行任意代码,如果您与编写不佳的(或 C)库接口一次或两次。

于 2011-07-28T08:56:35.623 回答
0

在哪里catch?如果它在同一范围内 -delete可以在那里处理,否则您的 #2 是正确的选择。当然,假设您不想像您自己在 PS 中提到的那样以正确的方式进行操作...

于 2011-07-28T08:56:05.953 回答
0

这取决于某物是什么。如果计算something可以抛出异常,不,它不会很好。您必须通过使用堆栈分配的变量(在作用域的末尾被销毁)或使用各种智能指针(std 库、boost、选择)来处理您获取的每一个资源。

于 2011-07-28T08:56:43.360 回答
0

正确的方法是使用RAII模式。与其使用原始指针,不如将其包装在一个对象中,该对象在其析构函数中处理释放内存,例如 a std::wstringor std::unique_ptr

于 2011-07-28T08:57:48.860 回答
0

如果您明确使用未包装的新产品,则必须明确使用删除。所以在这种情况下你必须捕获异常然后调用delete。

正如您所说,正确的方法是将缓冲区包装在将调用其析构函数的 C++ 类中。对于一个简单的缓冲区,开销最小的类可能是 std::vector,但智能指针例如 boost::scoped_ptr 也可以工作。

于 2011-07-28T08:58:13.913 回答