2015-04-24 14 views
15

我想知道,下面的代碼是否會導致不確定的行爲:是否上溯造型一個空指針導致未定義行爲

#include <cstddef> 
#include <cstdio> 

struct IA { 
    virtual ~IA() {} 
    int a = 0; 
}; 
struct IB { 
    virtual ~IB() {} 
    int b = 0; 
}; 
struct C: IA, IB {}; 

int main() { 
    C* pc = nullptr; 
    IB* pib = pc; 
    std::printf("%p %p", (void*)pc, (void*)pib); 
} 
+0

這使用C++ 14:https:// ideone生成'0 0'。com/iefRnb – EdChum

+0

多重繼承(以及指針調整)的例子會更有趣。 – Quentin

+0

@Quentin同意。要更新這個問題。 – Lingxi

回答

7

斯特勞斯討論這種情況下,第4.5節的his 1989 multiple inheritance paper [PDF]

解決方案是爲了詳細說明 轉換(鑄造)操作測試的指針值0 [...]

增加的複雜性和運行時間開銷是測試和 增量。

該實現顯式檢查空值並確保轉換的結果仍爲空值。這在C++ 98中是正確的,並且在C++ 11和nullptr中沒有改變。

這對於多個基類尤其重要,其中從派生類到基類之一的轉換可能需要更改指針的實際值。

在您的示例中,內存中的C的佈局將首先包含IA的字節,後面跟着IB的字節。投到IA是繁瑣的,因爲指向C開頭的指針也將指向IA的一部分C的開頭。另一方面,如果投射到IB,則需要將C指針移動IA的大小。在nullptr情況下執行這種轉換會在轉換後導致非空指針,因此對空值進行特殊處理。

pointed out by aschepler,在標準的相關部分是[conv.ptr]§4.10:

類型的prvalue「指針CVD」,其中D是一個類型,也可 轉換爲「指向cvB」的指針的預值,其中B是基地 類別D。 [...]轉換的結果是指向派生類對象的基類子對象的指針 。將空指針 的值轉換爲目標類型的空指針值。

+0

您的回答提供了有關實施的寶貴見解。非常好的工作! – Lingxi

+0

@靈溪謝謝:)我真的很喜歡Stroustrup的那篇論文。這對於理解編譯器如何實際處理引擎蓋下的多重繼承非常有用。 – ComicSansMS

+0

如果你可以通過引用標準更新你的答案(比如@aschepler所做的),那將是最好的選擇。對迂腐標準和一些實際實現問題的理解是很好的。 – Lingxi

8

上溯造型空指針被良好定義的給你另一個空指針:

4.10p3:

類型的prvalue 「指針CVD」,其中D是一個類的類型,可以轉換爲類型爲「指針cvB」的預值,其中BD的基類。 ...空指針值被轉換爲目標類型的空指針值。

相關問題