【问题标题】:Behaviour of reference(&) data member pointing to stack variable指向堆栈变量的引用(&)数据成员的行为
【发布时间】:2014-06-17 09:51:06
【问题描述】:

我遇到了一个关于使用引用数据成员的示例源代码,我对输出感到困惑。这是示例代码。

class Test {
private:
    int &t;
public:
    Test (int y):t(y) {  }
    int getT() { return t; }
};

int main() {
    int x = 20;
    Test t1(x);
    cout << t1.getT() << "\n"; // Prints 20 as output. however y has already been destroyed but still prints 20.
    x = 30;
    cout << t1.getT() << endl; // Prints Garbage as output Why ? Ideally both steps should be Garbage.
    return 0;
}

为了更加混乱,这里还有一段代码用于同一类

int main() {
    int x = 20;
    int z = 60;
    Test t1(x);
    Test t2(z);
    cout<<t1.getT()<<"\n"; // Prints 60! WHY? Should print garbage
    cout<<t2.getT() << "\n"; // Prints Garbage  
    cout<<t1.getT() << endl; // Prints Same Garbage value as previous expression
    return 0;
}

【问题讨论】:

    标签: c++ reference stack scope


    【解决方案1】:

    x 是通过 使用 temporary 传递的,所以 t 是对 那个临时 的引用,而不是 x .构造函数返回后,该临时对象将被销毁。您的代码有未定义的行为。任何东西都可以作为输出。你的问题可以通过传递xlike的引用来解决

    Test (int& y):t(y);
    

    但这不是一个好主意。可能会出现x超出范围但Test对象仍在使用的情况,然后会出现同样的问题。

    【讨论】:

      【解决方案2】:

      你的构造函数:

      Test (int y):t(y) {  }
      

      将 t 设置为对 y 的引用,y 是堆栈上的本地(临时)变量,而不是调用函数中的变量。当您更改调用函数中的变量值时,它不会更改您创建的对象中的任何内容。

      引用是对在构造函数生命周期结束时丢失的临时变量的事实意味着 getT() 返回一个未定义的值。

      每次调用int getT() 都会访问 y 的内存地址。该内存地址在构造函数结束时从堆栈中释放,因此它指向不在堆栈或堆上的内存,因此可以随时重用。重用时间没有定义,取决于编译器和依赖库建立的其他操作。 int getT() 的返回值取决于操作系统上影响内存的其他元素、编译器类型和版本以及操作系统等。

      【讨论】:

      • 实际上我关心的是在 y 的内存地址上刷新值的时间。在第一个 getT 语句中,它打印已经被销毁的地址的值,但仍然打印一些值而不是垃圾值。
      • getT() 导致未定义的行为(不仅仅是“返回未定义的值”) - 任何事情都可能发生
      • 我添加了第三段,其中包含有关未定义行为的一些详细信息。值得指出的是,在您的示例中,第一个 getT() 似乎可以工作,但它仍然未定义 - 如果您运行它 1000 次或在另一个操作系统上运行它,您可能会得到不同的结果!
      【解决方案3】:

      现在我明白了。是的,它是未定义的,但要回答我的问题,为什么它在打印垃圾之前打印 20 或 60?实际上答案是 20 和 60 这两个值都是垃圾,理想情况下,两个 getT 函数调用都应该打印垃圾,但它没有。因为在Test t2(z); cout<<t1.getT()<<"\n"; 之间没有其他指令 但是对于下一条语句,\n 作为指令工作,同时堆栈清除值。

      【讨论】:

        猜你喜欢
        • 2020-01-03
        • 1970-01-01
        • 2019-06-27
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-03
        相关资源
        最近更新 更多