Превышает ли повышение значение null указатель на поведение undefined

Мне интересно, приводит ли следующий код к undefined:

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

Ответы

Ответ 1

Stroustrup обсуждает этот случай в разделе 4.5 свой 1989 многократный документ наследования [PDF]:

Решение заключается в разработке операции преобразования (литья) в тест для значения указателя 0 [...]

Добавленная сложность и накладные расходы во время выполнения - это тест и приращение.

Реализация проверяет явно для нулевых значений и гарантирует, что результат приведения остается нулевым значением. Это было верно в С++ 98 и не изменилось с С++ 11 и nullptr.

Это особенно важно в случае нескольких базовых классов, где приведение из производного класса в один из базовых классов может потребовать изменения фактического значения указателя.

В вашем примере макет C в памяти сначала будет содержать байты для IA, а затем байты для IB. Отбрасывание до IA является треугольником, поскольку указатель на начало C также укажет на начало IA части C. С другой стороны, для каста до IB требуется сдвиг указателя C на размер IA. Выполнение этого сдвига в случае nullptr приведет к ненулевому указателю после актера, следовательно, специальная обработка для нулей.

В качестве отмеченного aschepler, соответствующий раздел стандарта [conv.ptr] §4.10:

Значение типа "указатель на cv D", где D - тип класса, может быть преобразуется в prvalue типа "указатель на cv B", где B является базой класс [...] of D. [...] Результат преобразования - указатель на субобъект базового класса объекта производного класса. Нулевой указатель значение преобразуется в значение нулевого указателя для типа адресата.

Ответ 2

Ускорение нулевого указателя хорошо определено, чтобы дать вам еще один нулевой указатель:

4.10p3:

Значение типа "указатель на cv D", где D - тип класса, может быть преобразовано в prvalue типа "указатель на cv B", где B является базовым классом D.... Значение нулевого указателя преобразуется в значение нулевого указателя для типа назначения.