2017-01-15 40 views
3

這是從invoking the copy constructor within the constructor分拆。在初始化列表的末尾是否完全構建了一個對象?

我相信一個對象是完全形成的,並且可以期望在初始化列表末尾表現出來(編輯:我對此有錯誤!)。具體來說,成員函數和從構造函數本身中訪問本地狀態的行爲將與其他任何成員函數完全相同。

雖然這似乎是一個有點爭議的觀點,但替代方案是隻有一旦構造函數正常返回,對象完全形成。

以下是對此的一個快速&髒測試用例,它顯示了初始化列表中提到的所有成員字段被初始化,以及沒有得到默認構建的成員字段。

#include <cstdio> 

struct noise 
{ 
    noise() { printf("noise default constructed\n"); } 
    noise(int x) { printf("noise integer constructed %u\n", x); } 
    ~noise() { printf("noise dtor\n"); } 
}; 

struct invoke : public noise 
{ 
    noise init; 
    noise body; 
    invoke() : noise(3), init(4) 
    { 
    body = noise(5); 
    throw *this; // try to use the object before returning normally 
    } 
    ~invoke() { printf("invoke dtor\n"); } 
}; 

int main() 
{ 
    try 
    { 
     invoke i; 
    } 
    catch (...) 
    { 
    } 
} 

這版畫,我的機器上至少,

noise integer constructed 3 
noise integer constructed 4 
noise default constructed 
noise integer constructed 5 
noise dtor 
noise dtor 
noise dtor 
noise dtor 
invoke dtor 
noise dtor 
noise dtor 
noise dtor 

一如往常,這是很難區分的作品,如規定從作品-AS-我的編譯器實現的!這實際上是UB嗎?

回答

5

在初始化列表末尾是否完全構建了一個對象?

不,它不是。對象this在構造函數執行結束時完全構造。

但是,所有成員都由初始化程序列表的末尾構建。

區別很微妙,但它與解析器的執行有關非常重要。如果this對象在執行構造函數期間引發異常,則每個構造的成員和基類都會被破壞。 this對象的析構函數只有在完全構造後纔會執行。

From the cppreference

  • 因爲如果它,或任何其子對象的,由不同於平凡缺省構造以外的任何初始化類或聚合類型的任何對象,當初始化結束壽命開始。
  • 對於析構函數並不平凡的類類型的任何對象,當析構函數的執行開始時,生存期結束。
+0

有趣。除了析構函數以外,對一個對象的函數是否需要一個完全構造的對象或一個擁有所有成員的對象? –

+0

取決於該功能,可以在施工和銷燬過程中調用正常的成員函數。有一個虛擬功能的捕獲,他們可能不會調用您期望的實現,並且經常建議在施工期間不要調用。 – Niall

+0

這非常令人興奮。謝謝 –

5

你的例子是明確定義的行爲,但只是如此。

要清楚的是,我們看到的"invoke dtor"系列是來自您的例外的破壞,而不是頂級i對象。

該類的每個成員都在構造函數體開始的時候被初始化,儘管在構造函數體完成之前對象本身沒有被初始化。這就是爲什麼~invoke未在頂級調用對象上調用的原因。

throw *this表達從*this複製初始化一個invoke對象,它允許。 (該標準明確規定「在構造或銷燬過程中可以調用成員函數」)。您的複製初始化是默認的,它只是初始化所有已初始化的成員。

然後,因爲您的構造函數體正在通過異常退出,所有已初始化的成員都被破壞,異常會被傳播,捕獲並處置,並調用~invoke,並反過來銷燬這些成員。

+0

這非常徹底,謝謝 –

相關問題