内存分配和Try-Catch块
Memory Allocation and Try-Catch Block
我有一个函数来分配一个2D数组,以便不花费比我需要更多的内存:
_>
template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
Xvar** mem;
unsigned int size, i;
size = rows * cols;
mem = new Xvar* [rows];
mem [0] = new Xvar [size];
for (i=1;i<rows;i++)
mem [i] = &mem [0][i*cols];
return mem;
}
现在,我需要检查是否分配了内存。(处理内存分配错误)而不降低函数的性能
我应该为每个内存分配使用一个try-catch块,还是只为函数使用一个唯一的try-catch块?
template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
Xvar** mem;
unsigned int size, i;
size = rows * cols;
try {
mem = new Xvar* [rows];
}
catch (...) { assert (...) }
try {
mem [0] = new Xvar [size];
} catch (...) { assert (...) }
for (i=1;i<rows;i++)
mem [i] = &mem [0][i*cols];
return mem;
}
或者像
template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
try {
Xvar** mem;
unsigned int size, i;
size = rows * cols;
mem = new Xvar* [rows];
mem [0] = new Xvar [size];
for (i=1;i<rows;i++)
mem [i] = &mem [0][i*cols];
return mem;
}catch (...) { assert (...) }
}
我认为,第二种方式是不推荐的,因为,如果第一个新失败,mem是NULL,因此,如果我们执行mem[0],我们正在访问未分配的内存,因此应用程序在此时失败,并且无法捕获错误。
在第二种方法中,如果第一个new
失败,则求值立即跳转到catch块,甚至不会尝试访问mem[0]
。
在任何情况下,如果您想允许分配失败并容易地检测到这一点,您可能应该使用nothrow
变体,如果分配失败,它只返回NULL
。比如
mem = new (nothrow) Xvar*[rows];
if (!mem) {
// allocation failed, do whatever you want
}
mem[0] = new (nothrow) Xvar[size];
if (!mem[0]) {
// allocation failed, do whatever you want
}
根本不捕获异常,只需在函数展开时使用RAII清理内存:
template <class Xvar> Xvar** New2 (unsigned int rows,unsigned int cols)
{
unsigned int size = rows * cols;
std::unique_ptr<Xvar*[]> mem(new Xvar* [rows]);
mem[0] = new Xvar [size];
for (i=1; i<rows; i++)
mem[i] = &mem[0][i*cols];
return mem.release();
}
- 如果第一个
new
失败,你的函数没有做任何事情,没有泄露任何内存:std::bad_alloc
被抛出,这就是它 - 如果第二个失败,
unique_ptr
析构函数会处理那个内存,所以你还是可以的。 - 接下来的三行不能抛出,所以没有什么可以导致第二次分配泄漏
正如GmanNickG所指出的,这仍然是可怕的代码。这是你要的那个糟糕的代码,但我不想给人留下我支持原始设计的印象。我不喜欢。这是可怕的。
一旦调用者成功地获得了他们的Xvar**
,处理它的唯一方法是:
int **ii = New2<int>(x, y);
...
delete [] ii[0];
delete [] ii;
易碎且令人不快。两个更好的设计是:
使用一个真正的矩阵/2d-array模板类来管理存储,并且可以按值返回。然后,当该值对象超出
作用域时,内存将被回收。使用带有自定义删除器的智能指针
template <typename T> struct 2dDelete { void operator() (T **rows) { delete [] rows[0]; delete [] rows; } }; template <typename T> std::unique_ptr<T*[], 2dDelete<T>> 2dNew (unsigned rows, unsigned cols) { unsigned size = rows * cols; std::unique_ptr<Xvar*[]> tmp(new Xvar* [rows]); tmp[0] = new Xvar [size]; for (i=1; i<rows; i++) tmp[i] = &tmp[0][i*cols]; // hand-over from the intermediate pointer (which only owned the // top-level row allocation) to the caller's pointer (which will // own, and clean up, the whole thing). return std::unique_ptr<T*[], 2dDelete<T>> arr(mem.release()); }
相关文章:
- 编译器是否必须始终删除 try-catch 块(如果它被证明是非抛出的)
- 有没有更好的方法来处理异常? try-catch块真的很丑
- 我可以使用 try catch 语句来捕获任何错误而不是具体错误吗?
- 在大型应用程序的main上使用try-catch
- RapidXML 节点在 try catch 块中具有正确的值,但它在块外为 nullptr
- 提取 try-catch 时出现运行时错误
- std::unique_ptr 在 try-catch 块中未捕获取消引用异常
- 何时删除 try-catch 块中的指针
- 是否有理由大多数/所有 try-catch 示例只对 throw 语句使用 void 子函数
- 循环try..catch ..确保输入有效或使用控制语句
- 构造函数中的异常:init() 方法、指针、大型 try/catch 或
- C++ C2509 在讲师的定义中使用 try: - catch
- 为什么未达到的 try-catch 块会增加运行时时间
- 在 C++ 中使用 try-catch 进行删除 [] 或删除操作是否必要
- ex.nested try-catch中的什么()更改
- 为什么 c++ try-catch 块不能在 ubuntu 上与 g++ 一起使用?
- 格式化文件异常被 try catch 块忽略
- libpng错误不会被try/catch块捕获
- Try/catch块用于在构造函数内部将简单内存分配到公共原始指针
- 内存分配和Try-Catch块