C++ 指向堆栈变量的引用(&;)数据成员的行为

C++ 指向堆栈变量的引用(&;)数据成员的行为,c++,reference,stack,scope,C++,Reference,Stack,Scope,我遇到了一个关于使用引用数据成员的示例源代码,我对输出感到困惑。下面是示例代码 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

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

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;
}
类测试{
私人:
国际电讯,;
公众:
测试(inty):t(y){}
int getT(){return t;}
};
int main(){
int x=20;
试验t1(x);
cout
x
是使用临时值通过值传递的,因此
t
是对该临时值的引用,而不是
x
。该临时值将在构造函数返回后被销毁。您的代码具有未定义的行为。任何内容都可以作为输出。您的问题可以通过传递对
x
的引用来解决

Test (int& y):t(y);
但这不是一个好主意。在某些情况下,
x
超出了范围,但仍然使用了
Test
对象,那么同样的问题也会出现。

x
是使用临时值传递的,因此
t
是对该临时值的引用,而不是
x
。该临时值将在const之后被销毁构造函数返回。您的代码有未定义的行为。任何东西都可以作为输出。您的问题可以通过传递对
x
的引用来解决

Test (int& y):t(y);
但是这不是一个好主意。在某些情况下,
x
超出了范围,但是仍然使用
Test
对象,那么同样的问题也会出现。

您的构造函数:

Test (int y):t(y) {  }
将t设置为对y的引用,y是堆栈上的局部(临时)变量,而不是调用函数中的变量。更改调用函数中的变量值时,它不会更改所创建对象中的任何内容

该引用指向一个临时变量,而该临时变量在构造函数生命周期结束时丢失,这意味着getT()返回一个未定义的值

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

构造函数:

Test (int y):t(y) {  }
将t设置为对y的引用,y是堆栈上的局部(临时)变量,而不是调用函数中的变量。更改调用函数中的变量值时,它不会更改所创建对象中的任何内容

该引用指向一个临时变量,而该临时变量在构造函数生命周期结束时丢失,这意味着getT()返回一个未定义的值


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

现在我知道了。是的,它没有定义,但要回答我的问题,为什么在打印垃圾之前打印20或60?实际上,答案是20和60都是垃圾,理想情况下都是getT函数calls应该打印垃圾,但它不会,因为在
测试t2(z)之间没有其他指令;

cout现在我明白了。是的,它是未定义的,但要回答我的问题,为什么它在打印垃圾之前打印20或60?实际上,答案是20和60都是垃圾,理想情况下,两个getT函数调用都应该打印垃圾,但它不打印。因为在
测试t2(z)之间没有其他指令;

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