有人可以描述一下处理以下情况的正确方法:
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
,它允许被调用的析构函数释放已分配的内存,只是好奇。
答案 0 :(得分:8)
你的见解是正确的。模式
Acquire some resource
Do something
Release resource
基本上是错误的,因为Do something
可能会抛出异常并泄漏资源。此外,您必须记住释放资源,这是一个肥沃的错误来源。
正如您所指出的,正确的方法是始终使用析构函数释放资源的对象。这在C ++中的名称为RAII。
这意味着例如。从不使用delete
外部析构函数,或者从不依赖手动关闭文件句柄,从不手动解锁互斥锁等。了解智能指针,并尽可能使用它们。
请注意,某些语言(不是C ++)提供了finally
关键字,它允许您执行一个指令块,而不管是否抛出异常。 C ++使用RAII,如果编写适当的析构函数,就不应该关注资源释放。
我对C ++ 0x有一个小实用程序there,它允许在块退出时执行任意代码,如果你与编写不好的(或C)库接口一次或两次。
答案 1 :(得分:0)
catch
在哪里?如果它在同一范围内 - delete
可以在那里处理,否则你的#2是正确的选择。当然,假设你不想像你自己在PS中提到的那样正确地做这件事......
答案 2 :(得分:0)
这取决于什么是什么。如果计算something
可以抛出异常,不行,那就不行了。您必须通过使用堆栈分配的变量(在范围的末尾销毁)或使用各种智能指针(std库,提升,选择)来处理您获得的每个资源。
答案 3 :(得分:0)
正确的方法是使用RAII模式。您应该将其包装在处理析构函数中释放内存的对象中,而不是使用原始指针,例如std::wstring
或std::unique_ptr
。
答案 4 :(得分:0)
如果明确使用未包装的新内容,则必须明确使用删除。因此,在这种情况下,您必须捕获异常,然后调用delete。
正如您所说,正确的方法是将缓冲区包装在将调用析构函数的C ++类中。对于一个简单的缓冲区,具有最小开销的类可能是std :: vector但是一个智能指针,例如boost :: scoped_ptr也可以。