首頁  >  問答  >  主體

c++ 临时变量问题?

#include <iostream>
#include <string>
using namespace std;

const string& Func()
{
    return "123";
}

int main()
{
    string s = Func();

    cout << s << endl;

    return 0;
}

const 引用不是会提升临时变量的生命期吗? 为什么返回函数内的临时变量会报错了? 我对const引用的理解哪里错了吗?

#include <iostream>
#include <string>
using namespace std;

const string& Func(const string& s)
{
    return s;
}

int main()
{
    string s = Func("123");

    cout << s << endl;

    return 0;
}

但是这段代码就可以了。 Func函数参数绑定到一个临时变量,然后返回这个临时变量的const引用,就没有问题?
why?

ringa_leeringa_lee2714 天前537

全部回覆(5)我來回復

  • 阿神

    阿神2017-04-17 13:34:43

    因為前者,「123」是在Func函數的內部,也就是函數的堆疊上,出了函數就沒有了。
    而後者「123」是在main函數的內部Func函數執行完了,控制流程回到了main函數還在。
    const引用會提高臨時變數的生命週期是指,臨時變數的生命週期本來只是創建該臨時變數的表達式,表達式結束後,被析構,const引用將其生命週期提升到該函數結束時(如果是全域const引用變量,那自然就是提升到整個程式的生命週期),函數結束被析構,而不會將其生命週期提升到函數外部,函數結束時,也會被析構掉的。
    const引用其實和右值引用差不多,都是將臨時變數的生命週期從這個表達式提升到函數。

    補充一點參考資料

    Whenever a reference is bound to a temporary or to a base subobject of a temporary, the lifetime of the temporary is extended to match the lifetime of the reference, with the follo exceptions

    • a temporary bound to a return value of a function

      in a return statement is not extended: it is destroyed imtely at the exendion . Such function always returns a dangling reference.

    • a temporary bound to a reference member in a constructor initializer list persists only until the constructor exits, not as long as the object exists. (note: such initialization is ill-formed 19696)

    • a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outs the full exlives the full exlives a reference, which outlives the full exliveion, . until C++14)
    • a temporary bound to a reference in the initializer used in a new-expression exists until the end of the full expression containing that new-expression, not as long as the initialized inj乾. expression, its reference member becomes a dangling reference.
    • In general, the lifetime of a temporary cannot be further extended by "passing it on": a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime。

    引自http://en.cppreference.com/w/cpp/language/reference_initialization

    翻譯一下前兩段,尤其註意加粗的字:
    無論何時一個綁定了一個臨時變數或一個臨時變數的基類子物件的引用,臨時變數的生命週期被擴展到與引用的生命週期相對應,除了一下幾個例外:
    一個在函數的return語句中對函數的回傳值的臨時綁定不會被延展:它會在return語句結束時立即被銷毀。這種函數總是回傳一個懸垂引用

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-17 13:34:43

    第一段程式main方法:
    改為:
    const string s = Func();

    回覆
    0
  • PHPz

    PHPz2017-04-17 13:34:43

    傳回函數內定義的局部變數是未定義行為。

    const string& Func()
    {
        return "123";  // 返回定义在函数 Func 里的局部变量 "123",是未定义行为。
    }  // 变量 "123" 在此处被销毁
    
    int main()
    {
        string s = Func();  // s 指向已被销毁的变量
    
        cout << s << endl;
    
        return 0;
    }
    const string& Func(const string& s)
    {
        return s;  // 返回函数外定义的变量的引用 s
    }
    
    int main()
    {
        string s = Func("123");  // s 指向定义在函数 main 里的局部变量 "123"
    
        cout << s << endl;
    
        return 0;
    }  // 变量 "123" 在此处被销毁

    回覆
    0
  • PHPz

    PHPz2017-04-17 13:34:43

    你這裡const是不會提升局部變數的生命週期的,局部變數是存放在棧上,函數回傳的時候對應的棧會被釋放,也就是局部變數也會被銷毀。你第一個程式不是局部變數宣告週期的問題,const是代表不能修改的意思,但是你的s變數沒有用const修飾,所以不能賦值。

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-17 13:34:43

    個人覺得,上面的回答都有些問題。 。 。
    看題主的代碼:

    #include <iostream>
    #include <string>
    using namespace std;
    
    const string& Func()
    {
        return "123";
    }
    
    int main()
    {
        string s = Func();
    
        cout << s << endl;
    
        return 0;
    }

      這段程式碼確實會報錯,但是只要把 const string& Func() 中的 & 去掉就可以了。出錯的原因並不是"123"在棧中,當函數返回時出棧導致的錯誤。而是,"123"本身是在靜態資料區的,當函數返回時實際返回的是"123"在靜態資料區的地址,該地址在函數Func中是局部變數(在堆疊中),此時,我們使用引用類型傳回該局部變數的(但是,會發生出棧操作),我們的參考變數被釋放了,就會出錯。但是,如果我們不使用& ,返回的時候我們實際上得到的是地址值的中間變數(函數的非引用返回值都會保存在中間變數中),此時堆疊操作是不影響我們取得正確的地址值的。

    回覆
    0
  • 取消回覆