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);
}
Upcasting a null pointer is well-defined to give you another null pointer:
4.10p3:
A prvalue of type "pointer to cv
D
", whereD
is a class type, can be converted to a prvalue of type "pointer to cvB
", whereB
is a base class ofD
. ... The null pointer value is converted to the null pointer value of the destination type.
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
”, whereD
is a class type, can be converted to a prvalue of type “pointer to cvB
”, whereB
is a base class [...] ofD
. [...] 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With