了解对象,范围,RAII的生命周期

时间:2011-03-19 21:05:52

标签: c++ scope raii

below code中,当我将一个未命名的A变量传递给B的ctor时,变量在该行之后被破坏。根据{{​​3}}:

  

临时对象被破坏了   结束他们的完整表达   部分。完整的表达是一个   表达式不是子表达式   其他一些表达方式。通常这个   意味着它结束于表示结束的; (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

2 个答案:

答案 0 :(得分:5)

你有一个C ++的棘手部分

member_a具有值20的绝对机会。您正在将未经定义的行为视为未经修改的行为。

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

如果要保留对对象的引用。您可以保留const引用,但有时最好使参数成为普通引用,这样您就不会意外地传递临时值(这并不总是有效,因为您可能需要通过引用传递const对象)。

答案 1 :(得分:1)

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

在A的析构函数中,尝试将“sign”设置为“-1”,看看会发生什么。可能性是对“WriteB”的调用将显示您已向已故对象发送消息。

现在尝试在b2的构造函数和对b2.WriteB的调用之​​间使用代码放置一堆堆栈,例如调用子例程。您现在可能会发现该调用会打印出不同的内容。