可能重复:
Can a local variable’s memory be accessed outside its scope?
代码:
#include <iostream>
using namespace std;
class B{
public:
int b;
B():b(1){}
~B(){cout << "Destructor ~B() " << endl;}
};
class A{
public:
B ob;
A()try{throw 4;}
catch(...){cout << "Catched in A() handler : ob.b= " << ob.b<<endl;}
};
int main()try{
A t;
}
catch(...){cout << "CATCHED in Main" << endl;}
输出:
Destructor ~B()
Catched in A() handler : ob.b= 1
CATCHED in Main
我的问题是如何访问其析构函数调用完成的对象b
的成员变量ob
。
答案 0 :(得分:8)
使用被破坏的对象是未定义的行为。这意味着您现在可能会遇到此行为,但没有什么可以保证您将在其他时间获得此行为。未定义的行为比常规错误更危险,因为它可能更难以检测,如此示例所示。
更新:在发表一些评论之后,我将解释为什么OP的代码会产生该输出。
try
功能块在C ++中是一个有点模糊的功能。您可以在try
块内围绕函数的整个主体,并使用其对应的catch
。这是,而不是:
void foo()
{
try
{
//...
}
catch (/*whatever*/)
{
//...
}
}
你可以写:
void foo()
try
{
//...
}
catch (/*whatever*/)
{
//...
}
这实际上并不太有用,但对于构造函数来说可能稍微有用,因为这是在try
块中包含初始化列表的唯一方法。因此,OP A
构造函数的代码等同于:
A()
try
: b()
{
throw 4;
}
catch(...)
{
cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
}
我说这只是非常有用,因为你不能在catch
块内使用你正在构建的对象;如果你扔进try
块,异常将离开构造函数体,因此从未构造对象,任何构造的数据成员将在进入catch
块之前立即被破坏。但它可能有一些用于记录目的。
现在,众所周知,构造函数(假设我们没有使用nothrow
版本)只能做两件事:
在这个构造函数中,我们抛出,但异常被catch
块捕获。那么现在发生了什么?什么将返回到调用构造函数的代码?我们不能返回一个构造对象,因为我们没有,所以只有一个选择:catch
块必须抛出。这实际上是标准在这种情况下的要求。如果我们不显式抛出,编译器将在throw;
块的末尾静默添加catch
指令。因此,详细说明一下,构造函数等效于以下内容:
A()
try
: b()
{
throw 4;
}
catch(...)
{
cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
throw;
}
这就是为什么异常被捕获两次的原因:一次在A
构造函数中,一次在main()
中。
答案 1 :(得分:3)
因为当对象被破坏时,它占用的实际内存仍然存在。但是,它的未定义的行为,可能会也可能不起作用。
答案 2 :(得分:2)
这可能是编译器中的错误。
当我运行你的代码时,析构函数以正确的顺序被调用。输出是:
Catched in A() handler : ob.b= 1
Destructor ~B()
我无法想象为什么catch
中main
被执行的原因。该例外已在A::A()
中找到。
<强>更新强>
我对编辑感到困惑。最初,它是初始化列表try / catch语法,它有所不同。现在我可以重现OP的输出,它确实是UB。我遇到了崩溃。