[英]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.