在调用析构函数后使用对象

时间:2012-10-25 11:39:18

标签: c++ exception destructor

  

可能重复:
  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

3 个答案:

答案 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版本)只能做两件事:

  1. 返回构造对象
  2. 抛出异常
  3. 在这个构造函数中,我们抛出,但异常被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()

我无法想象为什么catchmain被执行的原因。该例外已在A::A()中找到。

<强>更新

我对编辑感到困惑。最初,它是初始化列表try / catch语法,它有所不同。现在我可以重现OP的输出,它确实是UB。我遇到了崩溃。