我希望有一个简单的问题 - 当异常发生时,如何在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块中是否有规则不在堆上分配内存?
答案 0 :(得分:34)
研究 RAII习语(资源获取是初始化)!参见例如Wikipedia article on RAII。
RAII只是一般的想法。它被用于例如在C ++标准库的std::unique_ptr
或std::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_ptr
或unique_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; }