fre*_*low 20 c++ arrays memory-leaks exception resource-management
假设我有一个指向动态分配的10个元素数组的指针:
T* p = new T[10];
Run Code Online (Sandbox Code Playgroud)
后来,我想发布那个数组:
delete[] p;
Run Code Online (Sandbox Code Playgroud)
如果其中一个T析构函数抛出异常会发生什么?其他元素是否仍然被破坏?记忆会被释放吗?是否会传播异常,还是会终止程序执行?
同样地,当一个std::vector<T>被破坏而其中一个T析构者抛出时会发生什么?
我无法在标准中明确地看到它:
只是他们将以创建的相反顺序被调用
6如果delete-expression的操作数的值不是空指针值,则delete-expression将调用对象的析构函数(如果有)或要删除的数组的元素.在数组的情况下,元素将按地址递减的顺序销毁(即,与构造函数完成的顺序相反;见12.6.2).
并且即使抛出异常,也会完成内存释放:
7如果delete-expression的操作数值不是空指针值,则delete-expression将调用释放函数(3.7.4.2).否则,未指定是否将调用释放功能.[ 注意:无论对象的析构函数或数组的某个元素是否引发异常,都会调用释放函数.- 结束说明 ]
我在G ++中尝试了以下代码,它表明在异常之后不再调用析构函数:
#include <iostream>
int id = 0;
class X
{
public:
X() { me = id++; std::cout << "C: Start" << me << "\n";}
~X() { std::cout << "C: Done " << me << "\n";
if (me == 5) {throw int(1);}
}
private:
int me;
};
int main()
{
try
{
X data[10];
}
catch(...)
{
std::cout << "Finished\n";
}
}
Run Code Online (Sandbox Code Playgroud)
执行:
> g++ de.cpp
> ./a.out
C: Start0
C: Start1
C: Start2
C: Start3
C: Start4
C: Start5
C: Start6
C: Start7
C: Start8
C: Start9
C: Done 9
C: Done 8
C: Done 7
C: Done 6
C: Done 5
Finished
Run Code Online (Sandbox Code Playgroud)
这一切都回到了这个(非常古老的答案):
从析构函数中抛出异常
永远不要那样做.如果已经存在活动异常,std::terminate则会被称为:"砰,你死了".你的析构函数必须.不.扔.抗.
编辑:标准的相关部分(14882 2003),15.2构造函数和析构函数[except.dtor]:
15.2.3 为从try块到throw-expression的路径构造的自动对象调用析构函数的过程称为"堆栈展开".[注意:如果在堆栈展开期间调用的析构函数以异常退出,则调用terminate( 15.5.1).所以析构函数通常应该捕获异常,而不是让它们从析构函数中传播出来. - 尾注]
玩游戏的测试用例(在现实生活中,抛出衍生出来的东西std::exception,永远不要扔int或其他东西!):
#include <iostream>
int main() {
struct Foo {
~Foo() {
throw 0; // ... fore, std::terminate is called.
}
};
try {
Foo f;
throw 0; // First one, will be the active exception once Foo::~Foo()
// is executed, there- ...
} catch (int) {
std::cout << "caught something" << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
5.3.5.7如果delete-expression的操作数值不是空指针值,则delete-expression将调用解除分配函数(3.7.3.2).否则,是否未调用是否将调用释放功能.[注意:无论对象的析构函数或数组的某个元素是否引发异常,都会调用释放函数. - 结束说明]
找不到任何关于析构函数的内容除外
在数组的情况下,元素将按地址递减的顺序销毁(即,与构造函数完成的顺序相反;见12.6.2).
我想投掷后没有更多的析构函数被调用,但我不确定.