skip to content
Mehdi Mehdikhani
Table of Contents

nullptr is C++11’s answer to the problems with NULL and 0 for null pointers. It’s type-safe and eliminates a whole class of bugs.

What nullptr Actually Is

nullptr is a keyword that represents a null pointer constant. Unlike NULL (which is usually just 0), nullptr has its own type: std::nullptr_t.

int* p1 = nullptr; // Clear intent
int* p2 = NULL; // Old way, potentially problematic
int* p3 = 0; // Even worse - just an integer

The Problem with NULL

NULL is typically defined as 0, which creates ambiguity:

void func(int x);
void func(char* p);
func(NULL); // Which function gets called? Usually the int version!
func(0); // Definitely calls func(int)
func(nullptr); // Definitely calls func(char*)

This ambiguity has caused countless bugs in C and older C++ code.

Why nullptr Is Better

  1. Type safety: nullptr only converts to pointer types:
int x = nullptr; // Compilation error
bool b = nullptr; // Compilation error (good)
int* p = nullptr; // OK
  1. Template compatibility: Works correctly with templates:
template<typename T>
void process(T value) {
if (value == nullptr) { // Only works if T is a pointer type
std::cout << "Null pointer" << std::endl;
}
}
  1. Overload resolution: Chooses the right function:
void handle(int value) { std::cout << "Integer: " << value << std::endl; }
void handle(void* ptr) { std::cout << "Pointer" << std::endl; }
handle(0); // Calls handle(int)
handle(NULL); // Usually calls handle(int) - confusing!
handle(nullptr); // Always calls handle(void*)

When I Actually Use nullptr

Everywhere I used to use NULL:

  1. Pointer initialization:
int* data = nullptr;
MyClass* obj = nullptr;
  1. Pointer comparisons:
if (ptr != nullptr) {
// Safe to dereference ptr
}
// This pattern is so common, you can just write:
if (ptr) {
// ptr is not null
}
  1. Function parameters:
void process_data(const char* filename = nullptr) {
if (filename == nullptr) {
filename = "default.txt";
}
}
process_data(nullptr); // Use default filename
  1. Smart pointer resets:
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
ptr.reset(nullptr); // Reset to null - though reset() with no args works too

The Consistency Rule

I use nullptr everywhere, even where NULL would technically work:

// Consistent style
char* buffer = nullptr;
if (buffer == nullptr) {
allocate_buffer(&buffer);
}
return buffer != nullptr ? buffer : get_default_buffer();

Backward Compatibility

nullptr works fine with existing code:

// Legacy function expecting NULL
void legacy_func(void* p);
legacy_func(nullptr); // Works perfectly

The Pattern I Follow

Always use nullptr for null pointers, never NULL or 0. It’s clearer, safer, and more explicit about intent:

// Clear intent
std::unique_ptr<Resource> resource = nullptr;
Resource* raw_ptr = nullptr;
// Check for null
if (resource == nullptr) {
resource = std::make_unique<Resource>();
}

Real World Example

Here’s how it helps in practice:

class DatabaseConnection {
void* handle_ = nullptr; // Clear initialization
public:
bool connect(const char* connection_string = nullptr) {
if (connection_string == nullptr) {
connection_string = get_default_connection();
}
handle_ = establish_connection(connection_string);
return handle_ != nullptr;
}
void disconnect() {
if (handle_ != nullptr) {
close_connection(handle_);
handle_ = nullptr; // Clear state
}
}
};

nullptr is a simple change that makes code more robust and easier to understand. There’s no reason to use NULL anymore.