通过引用编辑对象是否可以确保函数返回后堆栈上的对象不会被销毁?

1 c++ oop pointers copy reference

我无法理解以下代码的输出

#include<iostream>
using namespace std;
template<typename T>
class foo{
    public:
        T a;
        foo(T b){
            this->a = b;
        }
        void print(){
            cout << a << endl;
        }
};
void goo(foo<int>& out){
    foo<int> a(10);
    out = a;
};
int main(){
    foo<int> a(5);    
    a.print();
    goo(a);
    a.print();
    return 0;
}
// Output: (C++17 g++-13)
// 5
// 10

Run Code Online (Sandbox Code Playgroud)

我想创建一个函数来创建一个新对象并返回对其的引用,以便我可以稍后为其他项目编辑该对象。但我发现在 C++ 中返回引用并不安全。所以我想到创建一个 void 函数,它将引用作为参数,我将在函数中创建一个对象,然后编辑引用。这似乎可行,但不应该,因为创建的新对象应该在函数返回后折叠,并且引用现在应该指向未分配的地址。访问它应该会出现分段错误。但我没有遇到任何这样的错误。

for*_*818 6

分配给引用不会重新绑定该引用。您无法重新绑定引用。分配给引用即分配给原始对象。


我想创建一个函数来创建一个新对象并返回对其的引用,以便我可以稍后为其他项目编辑该对象。

那不是你的代码所做的。那很好。因为在函数返回且 objec 消失后,您无法使用对函数局部对象的引用。这将导致未定义的行为。


通过一个更简单的例子也许可以更好地理解这一点。这就是你的函数的作用:

 void goo(int& a) {    // a is a reference to some int
    int x = 42;        // x is local to the function
    a = x;             // "some int" now equals 42
 }                     // x lifetime ends here !
Run Code Online (Sandbox Code Playgroud)

您担心但您的代码没有执行的操作如下:

 int& broken_code() { 
    int x = 42;       // x is local to the function
    return x;         // return a reference to x
 }                    // x lifetime ends here !
Run Code Online (Sandbox Code Playgroud)

由于x是函数的本地引用,因此返回的引用是悬空引用。如果不调用未定义的行为,则无法使用它。

然而,在您的代码中,foo<int> a(5);inmainfoo<int>本地的main. 您确实传递了一个引用goo并为该引用分配了一些内容。这相当于直接赋值给a. 您不会从该函数返回引用。


最后但并非最不重要的...

[...]访问它应该会出现分段错误。

那是一个误会。这是一种常见的情况,但也是一种非常危险的情况。错误的代码、具有未定义行为的代码不保证会崩溃。当您的代码具有未定义的行为时,实际上任何事情都有可能发生。预期崩溃是一种危险的误解,因为它让您相信代码要么崩溃,要么完全正常,这通常是错误的。为了确保您的代码没有未定义的行为,有一些用于静态或运行时分析的工具,但最终由您来确保代码执行其应该执行的操作。