Gal*_*axy 17 c++ exception-handling
我有一个别人写的潜在不稳定的类,我不得不创建该类的对象数组.我提到该类是不稳定的,因此它可能偶尔会在默认构造函数中抛出异常.我无权访问源代码,只能访问已编译的二进制文件.
当我使用这些类型的对象分配动态数组时new,这些坏对象之一可能会抛出异常.它抛出一个自定义异常,而不是std::bad_alloc.无论如何,我需要让程序从异常中恢复并继续使用,尽管设置了一些错误标志,什么不是.我认为我应该delete与数组关联的内存,以防止内存泄漏.
我的理由是,如果类抛出在数组中间某处构造元素的异常,那么该元素将无法正确构造,并且所有未来元素将被异常停止构造,但之前的元素将是因为在抛出异常之前发生了这种情况.我想知道,是不是一个好主意,打电话delete的catch (...) { }?我该如何解决这个内存泄漏?
Badclass* array = nullptr;
try {
array = new Badclass[10]; // May throw exceptions!
} catch (...) {
delete[] array;
array = nullptr;
// set error flags
}
Run Code Online (Sandbox Code Playgroud)
这是我在内存中可视化的方式.它是否正确?
array 0 1 2 3 4 5 6 7 8 9
___ __________________________________
| ---------->| :) | :) | :) | :) | :( | | | | | |
|___| |____|____|____|____|____|_|_|_|_|_|
Run Code Online (Sandbox Code Playgroud)
Who*_*aig 25
回答最后一个问题:
我该如何解决这个内存泄漏?
没有内存泄漏.泄漏只会在BadClass自身动态分配内容时发生,并且永远不会在其析构函数中释放它.既然我们没有忘记你的BadClass实施,也没有忘记猜测,那取决于你.new BadClass[N];泄漏内存本身的唯一方法是,如果它完成并且您稍后抛出对它的唯一引用,则您手动管理(array).
一个动态分配的数组,在其中一个元素的构造函数中抛出,将(a)为已经构造的元素以相反的顺序退出析构函数,(b)释放分配的内存,最后(c)主持实际投掷到最近的catch处理程序(或没有时的默认处理程序).
因为抛出发生,所以对结果数组指针的赋值永远不会发生,因此不需要delete[].
最佳示例:
#include <iostream>
struct A
{
static int count;
int n;
A() : n(++count)
{
std::cout << "constructing " << n << '\n';
if (count >= 5)
throw std::runtime_error("oops");
}
~A()
{
std::cout << "destroying " << n << '\n';
}
};
int A::count;
int main()
{
A *ar = nullptr;
try
{
ar = new A[10];
}
catch(std::exception const& ex)
{
std::cerr << ex.what() << '\n';
}
}
Run Code Online (Sandbox Code Playgroud)
产量
constructing 1
constructing 2
constructing 3
constructing 4
constructing 5
destroying 4
destroying 3
destroying 2
destroying 1
oops
Run Code Online (Sandbox Code Playgroud)
请注意,因为元素'5'的构造从未完成,所以它的析构函数不会被触发.然而,成员被成功构建的析构(未在本例证明以上,但如果你为它一个有趣的练习).
所有这些都说,无论如何使用智能指针.
在以下代码行中:
array = new Badclass[10];
Run Code Online (Sandbox Code Playgroud)
new Badclass[10]首先评估.如果抛出异常,则执行不会到达赋值.array保留其以前的值nullptr.它对调用删除无效nullptr.
评论部分提出的问题:
这种行为是否基于与堆栈展开相同的原理?
标准中的"异常处理"部分有助于我们了解在分配时抛出异常时会发生什么.
18例外处理[除]
......
18.2构造函数和析构函数[except.ctor]1.当控制从抛出异常的点传递到处理程序时,析构函数由本子条款中指定的进程调用,称为堆栈展开.
... 3.
如果除了委托构造函数之外的对象的初始化或销毁由异常终止,则为每个对象的直接子对象调用析构函数,对于完整对象,调用虚拟基类子对象,其初始化具有已经完成并且其析构函数尚未开始执行,除非在破坏的情况下,类似联合类的变体成员不会被销毁.子对象以完成构造的相反顺序销毁.在进入构造函数或析构函数的函数try-block的处理程序(如果有的话)之前,对这种破坏进行排序.
| 归档时间: |
|
| 查看次数: |
1717 次 |
| 最近记录: |