簡體   English   中英

C++ 參考的工作原理

[英]How C++ reference works

在 C++ 工作了 15 年后,我發現我並不完全理解引用。

class TestClass
{
public:
    TestClass() : m_nData(0)
    {
    }

    TestClass(int n) : m_nData(n)
    {
    }

    ~TestClass()
    {
        cout << "destructor" << endl;
    }

    void Dump()
    {
        cout << "data = " << m_nData << "  ptr = 0x" << hex << this << dec << endl;
    }

private:
    int m_nData;
};

int main()
{
    cout << "main started" << endl;

    TestClass& c = TestClass();
    c.Dump();

    c = TestClass(10);
    c.Dump();

    cout << "main ended" << endl;

    return 0;
}

// prints:
// main started
// data = 0  ptr = 0x0012FF54
// destructor
// data = 10  ptr = 0x0012FF54
// main ended
// destructor

我從這個測試中了解到TestClass實例是在堆棧上創建的(這是正確的嗎?)並由第一個TestClass構造函數初始化。 此實例何時分配:何時加載main函數或執行引用分配? 什么時候銷毀?

第二次引用賦值后,對象地址不變。 這是否意味着析構函數和構造函數應用於同一個內存區域? 還是內存被釋放(動態?在堆棧上?)並再次分配?

我知道關於堆棧和堆分配對象的生命周期、它們的構造函數和析構函數的一切,但我無法理解這個程序中究竟發生了什么。

編輯:謝謝大家。 我試圖在這個測試中重現一些其他(更復雜的)程序行為。 您的評論幫助我理解了我的錯誤和我正在與之抗爭的另一個程序......

固定代碼是:

int main()
{
    cout << "main started" << endl;
    TestClass t;

    TestClass& c(t);
    c.Dump();

    c = TestClass(10);
    c.Dump();

    cout << "main ended" << endl;
    return 0;
}

29.06.2022 的注意事項:在 Daniel Walker 的最新版本之后,這個問題看起來完全是廢話。 我對此不負責任。

您的代碼存在多個問題,最終沒有意義。 但是,讓我們破解它。

1)您只能將臨時綁定到const引用,從而延長其生命周期:

const TestClass & c = TestClass();

2)現在我們不能使用dump ,因為你沒有聲明它const

void Dump() const

3) 說c = TestClass()是一個作業。 但是, c現在是對 const 的引用,不能分配給它,因為分配是非常量的(出於顯而易見的原因)。 讓我們解決這個問題:

const_cast<TestClass&>(c) = TestClass(10);

現在我們已經為臨時但擴展的對象c分配了一個新值,一切都應該是這樣的:

main started
data = 0  ptr = 0x0xbfa8219c
destructor
data = 10  ptr = 0x0xbfa8219c
main ended
destructor

指針是相同的,因為只有一個對象,即c引用的(臨時)對象。 分配給它是一種通常是未定義行為的 hack,但出於本演示的目的,我們僥幸逃脫。

中間析構函數是第二個臨時TestClass(10)的析構函數。

TestClass& c = TestClass(); // TestClass() temporary doesn't persist beyond this expression.
c.Dump();

TestClass()創建一個臨時的,你不能引用它。

const TestClass& c = TestClass();

const限定將創建的臨時對象的生命周期延長到對象c的范圍。

TestClass& c = TestClass();

這甚至不會編譯!

嘗試將臨時引用綁定到非常量引用會導致編譯錯誤。

但是,您可以將臨時綁定到 const 引用:

{
   const TestClass& c = TestClass();
   //use c 
   //....
}//<-------- the temporary will be destroyed here.

在這種情況下,臨時變量的生命周期延伸到引用的生命周期,即當引用變量超出范圍時,臨時變量將被銷毀,如上所示。

1) 你不能得到對臨時對象的非 const 引用

2) 在行 c = TestClass(10); operator=(...) 被調用

一個好方法是比較對指針的引用......(引用通常在匯編中通過使用 ebx 寄存器以相同的方式實現)。 主要區別在於初始化后引用是恆定的......

但是,行const TestClass& c = TestClass(); const TestClass* const pc = &TestClass();平行因此對象將在堆棧​​上創建和銷毀,pc 仍將保持相同的地址。

暫無
暫無

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

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