2015-04-24 17 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的基类。 ...空指针值被转换为目标类型的空指针值。

相关问题