5

以下定義明確嗎?構造函數初始化列表中的循環依賴項

class A; 
class B; 

// define A, which takes B& in constructor 
// define B, which takes A& in constructor 

class C 
{ 
    A a; 
    B b; 
public: 
    C() : a(b), b(a) { /* stuff with a and b */ } 
} 

完整的示例在ideone.com

只要AB的構造函數對引用沒有做任何操作,它是安全/定義好的嗎?

+1

爲什麼downvote?讓我知道我該如何改進這個問題。 – Claudiu

+0

我不認爲編譯器允許你執行'a(b)',因爲當'a'被初始化時,'b'還沒有被初始化。 – user3528438

+0

@ user3528438:確實如此,ideone示例編譯並運行。但是,這是因爲我很幸運,還是因爲它在標準中有明確的定義? – Claudiu

回答

2

N4140 [class.cdtor]/1讀取:

對於具有一個非平凡構造方法的對象,參考任何非靜態成員或基類的構造函數前的對象 的開始執行結果在未定義的行爲。對於具有非平凡的析構函數的對象,在析構函數完成後引用該對象的任何非靜態成員或基類 執行會導致未定義的行爲。

雖然這段經文本身並不意味着行爲是否定義良好,但下面的例子說明了這一點。下面是摘錄:

struct B : public A { int j; Y y; }; // non-trivial 
extern B bobj; 
B* pb = &bobj; // OK 

因此,答案是:是的,你的情況的行爲,如果你沒有在A構造指的是b成員或基類是明確界定。

+0

這足夠直觀。因此,[user3528438的示例](https://ideone.com/V5uPyr)是未定義的行爲,因爲在m_a的構造函數運行之前訪問了m_a.m_value。感謝您挖掘參考資料! – Claudiu

+0

@Claudiu對,它絕對是UB。 –

+0

您可以將一個*引用*綁定到尚未構造的對象嗎?指針和引用的語義存在差異。例如,'int * p = nullptr; int&r = * p;'被認爲是UB,但是'int * r = &*p;'可以說不是UB(例如C明確地允許它)。 – dyp