fbpx

nullptr represents a null pointer and while it has a value of zero, the type is not the same.

For a long time in C++ there was a common rule that said you shouldn’t overload methods with integral types and pointer types. You could and the compiler would let you but it would likely cause problems later.

First, let me describe the situation better. Let’s say you have a method called buy in an adventure game that allows your hero to purchase food, clothing, or just about anything. You want to create a couple versions of this method and overload them so they’re both called buy. That means they need different signatures and you decide that one will take a pointer to some other data structure that describes what item the hero wants to buy and how many. For the other method, you want it to just take an int. The int will be used to specify how many additional items to buy. Sort of like a repeat option. The idea is that you normally call buy with the pointer and can sometimes call buy with an int if you want to buy more of the same thing.

Maybe your hero lives in a modern age and is careful to avoid leaving any trail of past purchases. So you want to be able to call buy with a pointer value of null to clear out any record of the previous purchase. The problem comes when you try to call buy and pass either a literal value zero or NULL. NULL is a macro that’s a little easier to spot in code because it’s written in all caps. The compiler never sees the value NULL. It just sees the 0. Other than the fact you can’t really count on NULL being an int or a long, it’s the same thing as if you pass a zero directly to the buy method.

Now, what does this mean? Which overloaded method should be called? If you pass a zero or NULL as an int, then it will end up calling the buy method that takes an int. I mean, you passed an int, so it makes sense that the compiler would select the method that takes an int. Instead of clearing out your previous purchase, you just bought zero more items as last time. That’s probably not what you wanted. And if NULL is defined to be a long, then your code won’t compile. Again, not the result you’re after.

The problem is caused by the fact that the only way to represent a pointer with a null value used to be to use an int value of zero. If all you have to choose from is a method that takes a pointer, then the compiler would treat that zero value as a pointer to null and go ahead and call the method. But when you also have a method that takes an int then that one gets called instead.

Listen to the episode for an explanation of using nullptr to solve this problem. Or read the full transcript of the episode below.

Transcript

For a long time in C++ there was a common rule that said you shouldn’t overload methods with integral types and pointer types. You could and the compiler would let you but it would likely cause problems later. Let me explain and then I’ll also explain how you can use nullptr as a much better solution.

First, let me describe the situation better. Let’s say you have a method called buy in an adventure game that allows your hero to purchase food, clothing, or just about anything. You want to create a couple versions of this method and overload them so they’re both called buy. That means they need different signatures and you decide that one will take a pointer to some other data structure that describes what item the hero wants to buy and how many. For the other method, you want it to just take an int. The int will be used to specify how many additional items to buy. Sort of like a repeat option. The idea is that you normally call buy with the pointer and can sometimes call buy with an int if you want to buy more of the same thing.

Maybe your hero lives in a modern age and is careful to avoid leaving any trail of past purchases. So you want to be able to call buy with a pointer value of null to clear out any record of the previous purchase.

So far all this seems reasonable even if it is a bit simplistic. This example is a lot better than many books or online articles that will just say you have a method called f, or foo, or sometimes func and leave it up to you to figure out what the method will do. I like to put a little story to my explanations and hope it’ll help you remember better.

The problem comes when you try to call buy and pass either a literal value zero or another common solution is to use a macro called NULL. The NULL macro is a little easier to spot in code because it’s written in all caps. All it is though is a macro that gets replaced with either a zero as an int or a zero as a long. the compiler never sees the value N U L L, NULL. It just sees the 0. Other than the fact you can’t really count on NULL being an int or a long, it’s the same thing as if you pass a zero directly to the buy method.

Now, what does this mean? Which overloaded method should be called? If you pass a zero or NULL as an int, then it will end up calling the buy method that takes an int. I mean, you passed an int, so it makes sense that the compiler would select the method that takes an int. Instead of clearing out your previous purchase, you just bought zero more items as last time. That’s probably not what you wanted. And if NULL is defined to be a long, then your code won’t compile. Again, not the result you’re after.

The problem is caused by the fact that the only way to represent a pointer with a null value used to be to use an int value of zero. If all you have to choose from is a method that takes a pointer, then the compiler would treat that zero value as a pointer to null and go ahead and call the method.

The general guidance was to avoid overloading methods with an int parameter type for one method and a pointer parameter type in the other method. As long as you don’t have this situation, then there’s no chance for confusion.

Until now. You have a better option starting with C++11. I’ll explain more right after this message from our sponsor.

With C++11, there’s a new type called a nullptr_t but you won’t use this directly. Instead when you want to pass null for a pointer value, use the keyword nullptr which is spelled n u l l p t r. The nullptr type can be automatically converted to any pointer of any other type.

Back to the earlier example, you can now write code that is clear and expected. If you call buy with an argument of zero, then you call the overloaded version that takes an int. And if you call buy with an argument of nullptr, then you call the version that takes a pointer. Because you now have a way to distinguish the two methods when calling them, it’s okay to overload methods between an integral type and a pointer type.

You benefit from using nullptr in other ways too. When you want to test a pointer for null or not then instead of comparing against zero, you can now compare against nullptr. This is easier to spot in your code and makes it clear that you’re testing a pointer type.

I’ll end this episode with one last thought about the methods and how they relate to templates. Whenever the compiler needs to convert a zero from an int to a pointer before calling a method, I just want to mention that it’s not really a conversion. This is called a type deduction. In other words, the compiler will choose the best method by deducing the types used to call the method. The compiler will first try to match a zero with an int and then if it can’t find a matching method, it’ll try other types such as a pointer. But when templates are involved, the ability to specify a pointer type directly is critical because the template type deduction won’t know that a zero should be a pointer.