2015-04-23 59 views
20

以下代碼的行爲是否定義良好?在構造之前綁定對象的引用

struct X { int i; }; // trivial 
struct Y : X { Y(){} }; // non-trivial 

extern X xobj; 
int& r1 = xobj.i; // #1 
X xobj; 

extern Y yobj; 
Y& r2 = yobj;  // #2 
// int& r3 = yobj.i; // #3 - this is UB according to the standard 
Y yobj; 

此代碼的靈感來自於C++標準中的示例,即草案N4140 [class.cdtor]/1。

這就是那款曰:

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

下面的例子顯示瞭如何指針可以和不可以綁定到對象。

那麼直觀看來,#1#2是明確的,如果沒有註釋而#3調用UB,但是,第一,實例並不規範,第二,有沒有在這個例子中引用的提及,第三和最重要的,上述段落並不意味着否則行爲是明確的。還是呢?或者也許我錯過了另一個相關的標準報價?

編輯:答案可能(可以說)是肯定的,如果對象具有靜態存儲時間,但它們也可以局部,如:

struct A { A(){} }; 
struct B { B(A&){} }; 

struct C { 
    B b; 
    A a; 
    C() : b(a) {} 
}; 

int main() { 
    C c; 
} 

其實,這是最初的靈感爲這個問題,看到Circular dependency in constructor initialization list

+3

「引用任何非靜態成員導致未定義的行爲」 - 引用正是引用所做的(因此名稱)。 – molbdnilo

+0

@molbdnilo我明白,但它不能解釋會發生什麼*否則*(例如,在構造函數開始之前爲類的構造函數開頭),這就是問題的關鍵。 –

+0

「指它」意味着提及它(這是英文單詞「refer」)。 –

回答

0

[...]有沒有在這個例子中引用的提及[...]

你的意思是,除了

[...] 任何非靜態成員[...]

從你引用的推移,我會說這行的原因未定義行爲:

int& r3 = yobj.i; // #3 

因爲你是:

[...]參考任何非靜態成員或基類的構造函數之前的對象的開始執行

此外,在該[]:

和最重要的,所述以上段落並不意味着否則行爲是明確的。

你說得對,這不:

當此國際標準 遺漏行爲或任何明確的定義可以預期

未定義行爲,當一個程序使用錯的構造或錯誤數據。

+0

#3調用UB,這是毫無疑問的。但是#2(直覺上)等於'Y * p2 =&yobj',它在標準示例中明確標記爲明確定義(但不是在規範文本中) –

+0

是嗎?那麼「基類」是什麼意思,如果不是'yobj'? – Siguza

+0

由於虛擬基類,引用非靜態數據成員和基類可能是UB。 vtable是在施工期間建立的,因此在施工開始之前,您既不能訪問也不能訪問虛擬基礎類。 – dyp

2

#2的行爲絕對是明確定義的。正如@dyp提到的,有關段落是在[basic.life]:

enter image description here

綁定glvalue yobj到參考是好的,因爲它的存儲持續整個節目的持續時間([鹼性。 stc.static]/1),並且引用被綁定到一個有效的對象 - 存活率一邊 - 滿足([dcl.ref]/5)中的要求。同樣,對於您展示的第二個示例,只要對A子對象的成員沒有執行任何操作,上面的段落也適用,因爲C的構造函數在分配的存儲上調用this引用。