Search code examples
c++language-lawyerimplicit-conversionnullptrupcasting

Does upcasting a null pointer lead to undefined behavior


I'm wondering whether the following code leads to undefined behavior:

#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);
}

Solution

  • Stroustrup discusses this case in section 4.5 of his 1989 multiple inheritance paper [PDF]:

    The solution is to elaborate the conversion (casting) operation to test for the pointer-value 0 [...]

    The added complexity and run-time overhead are a test and an increment.

    The implementation checks explicitly for null-values and ensures that the result of the cast is still a null-value. This was true in C++98 and has not changed with C++11 and nullptr.

    This is especially important in the case of multiple base classes, where a cast from a derived class to one of the base classes might require changing the actual value of the pointer.

    In your example, the layout of C in memory will first contain the bytes for IA, followed by the bytes for IB. Casting to IA is trival, as a pointer to the beginning of C will also point to the beginning of the IA part of C. Casting to IB on the other hand, requires shifting the C pointer by the size of IA. Performing this shifting in the nullptr case would lead to a non-null pointer after the cast, hence the special treatment for nulls.

    As pointed out by aschepler, the relevant section in the standard is [conv.ptr] §4.10:

    A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to cv B”, where B is a base class [...] of D. [...] The result of the conversion is a pointer to the base class subobject of the derived class object. The null pointer value is converted to the null pointer value of the destination type.