Let's say I have a C++ function that looks like this:
bool Foo(Bar* b)
{
if(b == nullptr) {
return false;
}
// Do stuff
return true;
}
Let's further say that, because of limitations with some of the tools I have that don't support any standards newer than C++03, I have this code in a header:
#if __cplusplus <= 199711L
#define nullptr (0)
#include <stdint.h>
#else
#include <cstdint>
#endif // End if C++03
My compiler will build this without warning or error. I know I don't have to cast nullptr
but is there a compelling reason that I should do it? That is, is there the potential for some bug to creep in relative to to Foo()
that using if (b == static_cast<Bar*>(nullptr))
would have avoided and that the compiler wouldn't have warned me about (in either C++03 or C++11 or later)?
My reasons for avoiding the cast would be:
- Adding the cast to every use of
nullptr
seems like it would make the code more cluttered/harder to read. - I haven't seen much (if any) code that does so.
Number 2 isn't a good reason in and of itself, so I'm wondering if it's done because it's more convenient for the code author and/or if it's because there really is no compelling reason to do so.
Edit based on proposed answer:
Questions are:
- If I'm stuck with C++03 now but still want to plan for C++11 in the future, is the best option to stick with legacy
NULL
being set to an integer value and all the best-practices that come with it? - If I'm stuck with something of the
#define NULL (0)
variety, should I always apply a cast? For example:if(b == static_cast<Bar*>(NULL))
is not something I see done very much and I'm wondering if this is out of laziness or if there are good reasons to do or not do this in the case of comparisons (like null pointer checks exemplified above).
Best Answer
This is a fantastically bad idea.
The expression
(0)
is (more or less) equivalent to the C++ definition of theNULL
. The thing is,nullptr
was invented specifically to deal with shortcomings of theNULL
.Therefore, pretending that they are in some way equivalent will only confuse readers. It will make people used to C++11 write code that has different behavior when compiled on C++03 compilers. For example:
C++11 tells us that this must call
foo(Bar*)
. But your C++03 macro will instead callfoo(int)
. Sincefoo(NULL)
would cause the same problem,nullptr
was invented to stop that.So having C++03 code that looks like C++11 code but behaves differently is a terrible idea.
nullptr
, by design, pretty much never needs to be cast to a specific pointer type. The only exception is if you're calling some kind of function of the form:But even then, you can just use
foo<ActualType>(nullptr)
and get the same effect asfoo(static_cast<ActualType*>(nullptr))
.Your not-
nullptr
needs casting in the same circumstances thatNULL
does. Indeed, since it is essentially equivalent toNULL
, you should just useNULL
. And therefore, you have all of the caveats thatNULL
has.And FYI: it's pretty much impossible to create a type in C++03 that has identical behavior to C++11's
nullptr_t
type. You can get close, by using implicit conversions and so forth. But there will always be corner cases where it doesn't work.So stop promising
nullptr
behavior that you cannot ensure.