2011-03-19 58 views
2

在​​中,当我将一个未命名的A变量传递给B的变量时,该变量在行后被破坏。据this answer了解对象的寿命时间,范围,RAII

临时对象是在充分表达的 最终摧毁他们的 一部分。完整的表达式是一个 表达式,它不是某个其他表达式的子表达式 。通常这个 意味着它结束于; (or) for if, while, switch etc.)表示结束 的声明。

我得到它,但类B怎么能知道它的mamber_a变量的值,它被破坏后?我知道A的拷贝是enver被调用的。这怎么可能?

#include <iostream> 
using namespace std; 

class A 
{ 
     int sign; 
     A(); 
     const A & operator=(const A &); 
public: 
     A(int x) : sign(x) { 
       cout << "A ctor : " << sign << endl; 
     } 

     void WriteA() const { 
       cout << sign << endl; 
     } 

     ~A() { 
       cout << "A dtor : " << sign << endl; 
     } 

     A(const A &) { 
       cout << "A copied : " << sign << endl; 
     } 
}; 

class B 
{ 
     int sign; 
     const A & member_a; 
public: 
     B(const A & aa , int ww) : sign (ww) ,member_a(aa) { 
       cout << "B ctor : " << sign << endl; 
     } 

     void WriteB() const { 
       cout << "Value of member_a :"; 
       member_a.WriteA();  
     } 

     ~B() { 
       cout << "B dtor : " << sign << endl; 
     } 
}; 

int main() { 
     A a(10); 
     B b1(a,1); 
     b1.WriteB();  

     B b2(A(20),2); 
     b2.WriteB(); 

     return 0; 
} 

输出是:

A ctor : 10 
B ctor : 1 
Value of member_a :10 
A ctor : 20 
B ctor : 2 
A dtor : 20 
Value of member_a :20 // Object A was destructed. Where does this 20 come from? 
B dtor : 2 
B dtor : 1 
A dtor : 10 

回答

5

你的C++

棘手的部分之一,它是纯粹的机会member_a的值为20你打什么审阅为未定义的行为。

当一个类保留对外部对象的引用时,程序员有责任确保该对象的生命周期比所引用的对象的持续时间更长。在这种情况下,当你打电话给member_a.WriteA();时,一个对象已经被销毁,因此你正在访问的内存可能不属于你(在这种情况下,它恰好在附近一个没有被覆盖的位置) )。

如果您要保留对对象的引用。您可以保留一个const引用,但有时最好将该参数设置为正常引用,以便您不会意外传递一个临时值(因为您可能必须通过引用传递const对象,所以这并不总是奏效)。

1

使用对被破坏对象的引用是一个“未定义的行为”。

在A的析构函数中,尝试将“sign”设置为“-1”并查看会发生什么。赔率是“WriteB”的调用将显示你已经发送了一个消息给已故的对象。

现在尝试使用b2的构造函数和b2.WriteB的调用之​​间的代码堆栈,例如调用子例程。你现在可能会发现这个调用打印出不同的东西。