2017-05-31 84 views
8

我發現this answer的問題"Does a const reference prolong the life of a temporary?",其中規定:這個const引用是否保留了它的生命?

只有當地const引用延長使用壽命。

恐怕我的標準並不清楚,以確定foo下面是否是本地const引用。

我的const std::string& foo下面是否延長在get_or的調用中創建的臨時std::string函數參數的生存期,還是我有一個懸掛參考?

#include <iostream> 
#include <boost/optional.hpp> 

struct Foo 
{ 
    const std::string& get_or(const std::string& def) 
    { 
     return str ? str.get() : def; 
    } 

    boost::optional<std::string> str; 
}; 

int main() 
{ 
    Foo f; 
    const std::string& foo = f.get_or("hello world"); 

    std::cout << foo << '\n'; 
} 
+2

接受的答案到你引用的問題(引用標準)明確說明了兩種情況,這是行不通的。你的例子是第二種情況:在函數調用中臨時綁定到引用參數。所以答案是否定的。 –

回答

4

const&在這種情況下不會延長壽命。考慮構建一個臨時的example here,然後嘗試打印它:它使用與您的代碼相同的構造,但我已經修改它以使對象構造和銷燬對用戶更加明確。

#include <iostream> 

struct reporting { 
    reporting() { std::cout << "Constructed" << std::endl;} 
    ~reporting() { std::cout << "Destructed" << std::endl;} 
    reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;} 
    reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;} 
    reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;} 
    reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;} 

    void print() const {std::cout << "Printing." << std::endl;} 
}; 

const reporting& get_or(const reporting& def) 
{ 
    return def; 
} 

int main() 
{ 
    const reporting& foo = get_or(reporting{}); 

    foo.print(); 
    return 0; 
} 

輸出:

Constructed 
Destructed 
printing. 

注意如何顯示printing.前的物體被破壞。

您可能想知道爲什麼代碼仍然完成,沒有可見的錯誤:這是未定義行爲的結果。有問題的對象不存在,但因爲它不依賴於狀態來調用它的方法,程序恰好不會崩潰。其他更復雜的例子不能保證這個功能不會崩潰或導致其他意想不到的行爲。

順便說一句,事情有點不同,如果臨時爲bound directly to the const&

#include <iostream> 

struct reporting { 
    reporting() { std::cout << "Constructed" << std::endl;} 
    ~reporting() { std::cout << "Destructed" << std::endl;} 
    reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;} 
    reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;} 
    reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;} 
    reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;} 

    void print() const {std::cout << "printing." << std::endl;} 
}; 

const reporting& get_or(const reporting& def) 
{ 
    return def; 
} 

int main() 
{ 
    const reporting& foo = reporting{}; 

    foo.print(); 
    return 0; 
} 

輸出:

Constructed 
printing. 
Destructed 

看到物體是如何不被破壞,直到用完之後。在這種情況下,對象會一直存在直到範圍結束。

+0

非常全面的答案,非常感謝! –

2

您通過太多引用傳遞字符串。

綁定臨時字符串的get_ordef參數延伸的字符串包含該函數調用中充分表達的端部的壽命,但結合def到的get_or返回值和的get_or返回值結合foo不要延長壽命。當您嘗試打印字符串時,該字符串已死亡。

+0

在關聯答案中,其中一條評論引用[this GOTW](https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/)它表示將const-ref綁定到臨時返回值是安全的。在我的情況下,返回值是來自參數*的臨時*這一事實使得這不適用? –

+0

@SteveLorimer:假設你在那個鏈接中談論Q1,'f'返回一個'string',而不是一個引用。您的'get_or'返回一個引用,並且該引用的引用不會通過將其綁定到更多引用而延長其生命週期。 – user2357112

+0

啊,是的,好的,謝謝! –

1

問題中的「臨時」是std::string-在調用get_or時創建的參數類型爲const char*的對象。此臨時對象的生命週期受到函數get_or的結束限制,並且返回對此臨時對象的引用並事後分配它不會延長生命週期。請看下面的代碼,它使用一個簡單的「自定義」串類,cout的建設和破壞:

class MyString { 
public: 
    MyString (const char* str) { 
     m_str = strdup(str); 
     cout << "constructor MyString - '" << m_str << "'" << endl; 
    } 
    ~MyString() { 
     cout << "destructor MyString - '" << m_str << "'" << endl; 
     free(m_str); 
    } 
    char *m_str; 
}; 

struct Foo 
{ 
    const MyString& get_or(const MyString& def) 
    { 
     cout << "Foo::get_or with '" << def.m_str << "'" << endl; 
     return def; 
    } 
}; 

int main() 
{ 
    Foo f; 
    const MyString& foo = f.get_or("hello world"); 
    cout << "usage of foo?" << endl; 
} 

輸出:

constructor MyString - 'hello world' 
Foo::get_or with 'hello world' 
destructor MyString - 'hello world' 
usage of foo? 

注意,調用析構函數之前,你將有機會使用foo

如果您直接爲指定,則情況會有所不同。同樣,壽命是直到函數main的結束,但它會在main,而不是在任何函數調用main使用:

const MyString& foo2 = MyString("hello world2"); 
cout << "usage of foo..." << endl; 

那麼輸出將是:

constructor MyString - 'hello world2' 
usage of foo... 
destructor MyString - 'hello world2' 
相關問題