我遇到过关于使用参考数据成员的示例源代码,我对输出感到困惑。这是示例代码。
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;
}
答案 0 :(得分:2)
x
使用临时按值传递,因此t
是对临时的引用,不是x
。构造函数返回后,该临时文件将被销毁。您的代码具有未定义的行为。任何东西都可以作为输出。您可以通过将引用传递给x
来解决您的问题
Test (int& y):t(y);
但这不是一个好主意。可能会出现x
超出范围但仍使用Test
对象的情况,然后会出现同样的问题。
答案 1 :(得分:2)
你的构造函数:
Test (int y):t(y) { }
将t设置为对堆栈的本地(临时)变量的引用,而不是对调用函数中的变量的引用。当您更改调用函数中的变量值时,它不会更改您创建的对象中的任何内容。
引用是指在构造函数生命周期结束时丢失的临时变量这一事实意味着getT()返回一个未定义的值。
每次调用int getT()
都会访问y的内存地址。该内存地址在构造函数的末尾从堆栈中释放,因此它指向不在堆栈或堆上的内存,因此可以随时重用。未定义重用的时间,并且取决于编译器和依赖库建立的其他操作。 int getT()
的返回值取决于操作系统上影响内存的其他元素,编译器类型和版本以及操作系统等。
答案 2 :(得分:1)
现在我明白了。是的,它是未定义的,但回答我的问题为什么它在打印垃圾之前打印20或60?实际上答案是20和60这两个值都是垃圾,理想情况下,两个getT函数调用都应该打印垃圾但不是。因为Test t2(z);
cout<<t1.getT()<<"\n";
之间没有其他指令
但对于下一个语句\ n作为指令工作,同时堆栈清除该值。