向上转换空指针会导致未定义的行为

Lin*_*gxi 15 c++ upcasting nullptr language-lawyer implicit-conversion

我想知道以下代码是否导致未定义的行为:

#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);
}
Run Code Online (Sandbox Code Playgroud)

asc*_*ler 9

向上转换空指针是明确定义的,以便为您提供另一个空指针:

4.10p3:

类型为"指向cv的 指针"的prvalue D,其中D是一个类类型,可以转换为类型为"指向cv的 指针"的prvalue B,其中B是一个基类D....空指针值将转换为目标类型的空指针值.


Com*_*sMS 8

Stroustrup在1989年的多重继承文件[PDF]第4.5节中讨论了这个案例:

解决方案是详细说明转换(强制转换)操作以测试指针值0 [...]

增加的复杂性和运行时开销是测试和增量.

该实现显式检查空值,并确保转换的结果仍为空值.这在C++ 98中是正确的,并且在C++ 11和C++中没有改变nullptr.

这在多个基类的情况下尤其重要,其中从派生类到其中一个基类的强制转换可能需要更改指针的实际值.

在您的示例中,C内存中的布局将首先包含字节IA,然后是字节IB.转换IA为trival,作为指向开头的指针C也将指向IA部分的开头C.投射到IB在另一方面,需要移位C通过的大小指针IA.在nullptr情况下执行此移位将导致在强制转换后的非空指针,因此对空值进行特殊处理.

正如aschepler指出的,标准中的相关部分是[conv.ptr]§4.10:

类型为"指向cv的 指针"的prvalue D,其中D是一个类类型,可以转换为类型为"指向cv的 指针"的prvalue B,其中B是一个基类[...] D.[...]转换的结果是指向派生类对象的基类子对象的指针.空指针值将转换为目标类型的空指针值.