我想拥有一个动态创建并返回2D数组的函数,或者当内存分配失败时通过异常without信息丢失after清理已分配的行:
double **create (int rows, int cols)
{
double **array = new double* [rows];
for (int x=0; x<rows; x++)
{
try { array[x] = new double [cols]; }
catch (exception &e)
{
x--;
for (; x>=0; x--)
delete[] array[x]; // clean up already allocated rows
delete[] array;
throw e; // pass exception
}
for (int y=0; y<cols; y++)
array[x][y] = 0; // initialize array
}
return array;
}
因此,我可以肯定的是,如果create throws引发了内存泄漏。但是我可以确定,所传递的异常e是“相同的”,就像被new直接抛出并没有被捕获一样?
例如
int main ()
{
double **d;
try { d = create (HUGE_x, HUGE_y); }
catch (exception &e)
{
// 1. e could be thrown by new double* [rows]
// e.g. if HUGE_x is already to huge
// 2. e could be thrown by throw e
// e.g. if after some rows no memory anymore
// in both cases: is e the same?
}
return 0;
}
或者是否需要在catch (bad_alloc &e)
函数中包含create
?还是仅适用于catch (...) { /* do clean-up*/ throw; }
?是否存在与C#中相同的问题,当重新抛出不是简单地使用throw;
时丢失堆栈跟踪吗?
还有另一个更普遍的问题:
void f () { throw Object(); } // or throw "help";
void main ()
{
try { f(); }
catch (Object &e) // or catch (char *)
{
// Where is the Object or C-String created on the stack in function f()
// since we aren't any more in function f() but we are dealing with
// references/pointers to a non-existent stack?
}
}
对于异常安全的内存管理,请使用RAII。与其使用原始指针和异常处理程序,不如将资源分配给一个类,该类将在销毁时释放它。这样,如果引发异常,一切都会自动清除。
在这种情况下,std::vector
是管理动态数组的合适RAII类:
vector<vector<double>> create (int rows, int cols) {
return vector<vector<double>>(rows, vector<double>(cols));
}
(请注意,将2D数组表示为大小为rows*cols
的单个数组可能会更有效,并且可以使用访问器为其中提供2D索引。但是,这个问题不在本文的讨论范围内,所以我不会进入乏味的细节)。
要回答您的问题,尽管如果您编写异常安全代码,它们在很大程度上是无关紧要的:
但是我可以确定,所传递的异常e是“相同的”,就像新的直接抛出并没有捕获到的一样?
不会;您将抛出一个通过复制或移动e
创建的,类型为exception
的新对象。
或者是否有必要在创建函数中包含
catch (bad_alloc &e)
?
那么您将不会捕获其他类型的异常。在这种情况下,这可能不是问题,但是如果您要像这样进行清理,那么您真的想捕获all异常。重申一下:不要使用异常处理程序进行清理。这非常容易出错。
或者它仅适用于
catch (...) { /* do clean-up*/ throw; }
吗?
将重新扔掉您想要的原始对象。 (除了您不应该一开始就捕捉任何东西之外。)
是否与C#一样存在同样的问题,当重新抛出不是简单地用
throw;
时丢失堆栈跟踪吗?
标准异常无论如何都不会给您堆栈跟踪。如果您具有带有堆栈跟踪的自定义异常类型,则取决于它是在复制/移动时生成新的还是在复制/移动现有的异常时生成新的异常。]
对象或C字符串在哪里?
异常处理机制在某个地方(不在即将解散的堆栈上)创建它,并在对其进行处理后销毁它。它没有确切说明它在哪里,而是它必须如何工作。
虽然这个问题到现在为止已经很老了,并且已经得到了足够的回答,但是我想补充说明重新抛出异常。在standard C ++ 11