因此,我正在尝试C ++展开,并遇到了这种奇怪的行为:在其中,我们有一个嵌套的try-catch块,而在外部,我们构造了一个对象。似乎在内部try-catch处理程序之一中捕获异常时破坏了该对象。
此外,如果我们如本例所示使用动态内存分配(我们在构造函数中使用new
,在析构函数中使用delete
,则该程序似乎在运行时产生诊断消息。
考虑此代码:
#include <stdio.h>
struct test {
test(int);
~test() throw(int);
int *b;
};
void f5() {
if (!printf(""))
throw 9;
}
test f(int, test) throw(int) { test tmp(6); f5(); return tmp; }
test::test(int a) : b(new int(a)) { printf("constructor test@%d\n", *b); }
test::~test() throw(int)
{
printf("destructor test@%d\n", *b);
delete b;
}
int main() {
test tmp(0);
try {
test tmp(1);
try {
f(7, tmp);
}
catch (int) {
printf("catch(int)@%d\n", 2);
try {
test tmphandler(3); f(7, tmp);
}
catch (int) {
printf("catch(int)@%d\n", 4);
}
}
printf("b = %d\n", *tmp.b);
f(7, tmp);
}
catch (int) { printf("catch(int)@%d\n", 5); }
}
这里是该程序的wandbox输出:
*** Error in `./prog.exe': double free or corruption (fasttop): 0x00000000020ee180 ***
....back-trace of addresses
constructor test@0
constructor test@1
constructor test@6
destructor test@6
destructor test@1
catch(int)@2
constructor test@3
constructor test@6
destructor test@6
destructor test@3
destructor test@33722768
我正在努力理解为什么在catch @ 2时,外部try范围内的对象被破坏了(即,在1上创建的对象)。
不确定标准,但是最近我正在阅读Deitel的有关C ++的书,下面是其中的一段:
17.4堆栈展开
当引发异常但未在特定范围内捕获异常时,函数调用堆栈将“展开”,并尝试在下一个外部try ... catch块中捕获异常。展开函数调用堆栈意味着未捕获异常的函数终止,该函数中已完成初始化的所有局部变量均被销毁,控制权返回到最初调用该函数的语句。如果try语句包含该语句,则会尝试捕获该异常。如果try块未包含该语句,则将再次发生堆栈展开。如果没有捕获处理程序捕获到此异常,则程序终止。
我希望这能回答您的问题。
首先,我缺少一个复制构造函数,因此在运行时缺少了诊断消息。第二-析构函数实际上是为从f
复制而来的tmp
参数调用的,因此1
的值会在销毁该对象时销毁,该对象在捕获异常时已正确销毁。这是不混淆的固定变体:
#include <stdio.h>
struct test {
test(const test&);
test(int);
~test() throw(int);
int *b;
};
void f5() {
if (!printf(""))
throw 9;
}
test f(int, test) throw(int) { test tmp(6); f5(); return tmp; }
test::test(int a) : b(new int(a)) { printf("constructor test@%d\n", *b); }
test::test(const test& a) : b(new int(7)) {}
test::~test() throw(int)
{
printf("destructor test@%d\n", *b);
delete b;
}
int main() {
test tmp(0);
try {
test tmp(1);
try {
f(7, tmp);
}
catch (int) {
printf("catch(int)@%d\n", 2);
try {
test tmphandler(3); f(7, tmp);
}
catch (int) {
printf("catch(int)@%d\n", 4);
}
}
printf("b = %d\n", *tmp.b);
f(7, tmp);
}
catch (int) { printf("catch(int)@%d\n", 5); }
}
输出为:
constructor test@0
constructor test@1
constructor test@6
destructor test@6
destructor test@7
catch(int)@2
constructor test@3
constructor test@6
destructor test@6
destructor test@7
destructor test@3
catch(int)@4
b = 1
constructor test@6
destructor test@6
destructor test@7
destructor test@1
catch(int)@5
destructor test@0