簡體   English   中英

當它被綁定到調用函數中的const引用時,它的返回值的生命周期如何擴展到調用函數的范圍?

[英]How is its lifetime of a return value extended to the scope of the calling function when it is bound to a const reference in the calling function?

“如果從函數返回一個值(不是引用),那么將它綁定到調用函數中的const引用,它的生命周期將擴展到調用函數的范圍。”

所以:案例A.

const BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

從函數GetBoundingBox()返回const BoundingBox類型的值

變體I :(將它綁定到const引用)

const BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

變體II :(將它綁定到const副本)

const BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

兩者都工作正常,我沒有看到l_Bbox對象超出范圍。 (雖然,我在變體1中理解,復制構造函數未被調用,因此稍微好於變體II)。

另外,為了比較,我做了以下更改。

案例B

BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

與變體:我

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

和II:

BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

對象l_Bbox仍然沒有超出范圍。 如何“將它綁定到調用函數中的const引用,它的生命周期將擴展到調用函數的范圍”,真正將對象的生命周期延長到調用函數的范圍?

我在這里錯過了一些小事嗎?

通常,臨時對象(例如函數調用返回的對象)的生命周期延伸到“封閉表達式”的末尾。 但是,對引用的臨時綁定通常會將其生命周期“提升”到引用的生命周期(可能是也可能不是調用函數的生命周期),但有一些例外情況。 這包含在12.2 / 5“臨時對象”中的標准中:

除了下面指定的內容之外,引用綁定的臨時對象或作為臨時綁定對象的子對象的完整對象的臨時對象的生命周期仍然存在。 綁定到構造函數的ctor-initializer(12.6.2)中的引用成員的臨時綁定將持續存在,直到構造函數退出。 在函數調用(5.2.2)中與引用參數的臨時綁定將持續存在,直到包含該調用的完整表達式完成為止。

有關更多信息,請參閱以下內容

一個可能有助於可視化正在發生的事情的示例:

#include <iostream>
#include <string>

class foo {
public:
    foo( std::string const& n) : name(n) { 
        std::cout << "foo ctor - " << name + " created\n"; 
    };
    foo( foo const& other) : name( other.name + " copy") { 
        std::cout << "foo copy ctor - " << name + " created\n";
    };

    ~foo() { 
        std::cout << name + " destroyed\n"; 
    };

    std::string getname() const { return name; };
    foo getcopy() const { return foo( *this); };

private:
    std::string name;
};

std::ostream& operator<<( std::ostream& strm, foo const& f) {
    strm << f.getname();
    return strm;
}


int main()
{
    foo x( "x");

    std::cout << x.getcopy() << std::endl;

    std::cout << "note that the temp has already been destroyed\n\n\n";

    foo const& ref( x.getcopy());

    std::cout << ref << std::endl;

    std::cout << "the temp won't be deleted until after this...\n\n";
    std::cout << "note that the temp has *not* been destroyed yet...\n\n";
}

哪個顯示:

foo ctor - x created
foo copy ctor - x copy created
x copy
x copy destroyed
note that the temp has already been destroyed


foo copy ctor - x copy created
x copy
the temp won't be deleted until after this...

note that the temp has *not* been destroyed yet...

x copy destroyed
x destroyed

首先,臨時對象的生命周期被擴展到綁定到它的const引用的生命周期,而不是“到調用函數的范圍”(盡管可能是那個奇怪的措辭“調用函數的范圍”) 。 這就是您的CASE A所示的內容,其中您將const引用附加到臨時。 只要參考存在,臨時就會繼續存在。 當引用結束其生命周期時,臨時對象也會被銷毀。

其次,你的CASE B只是形成錯誤,不可編譯。 即,

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

是非法的。 在C ++中附加非const引用到臨時是非法的。 如果您的編譯器允許它,它必須是編譯器的怪癖/擴展,這與C ++語言幾乎沒有關系。

關鍵是當按值返回時,該值將復制到您為該函數分配結果的變量中。 (就像你說的那樣 - 復制構造函數被調用)。 沒有終身延伸,你只需創建一個全新的對象。

通過引用返回時,您只需將指針傳遞給函數中定義的變量。 因此,不會創建新對象,只需在函數外部引用它即可。 在這種情況下,函數內部變量的生命周期被擴展。

通常,如果從函數返回值的對象,則在賦值表達式完成時將銷毀所述對象:

myclass X = getX(); // after copy constructor, the returned value is destroyed
                    // (but you still hold a copy in X)

在您描述的情況下,稍后將銷毀返回的值,允許您使用它:

const myclass& X = getX();
cout << X.a << endl; // still can access the returned value, it's not destroyed

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM