Origem do NULL
A macro NULL acompanha o C desde seus primórdios e foi herdada pelo C++ como forma de representar um ponteiro que não aponta para nenhum endereço válido. Sua definição concreta varia entre implementações:
// Definições típicas encontradas em headers padrão
#define NULL ((void*)0) // estilo C
#define NULL 0 // estilo C++ mais comum
O problema central aparece no segundo caso: quando NULL é apenas o número inteiro 0, o compilador perde a informação de que se tratava de um ponteiro. Isso gera conversões indeseajdas e chamadas ambíguas em código moderno.
A introdução do nullptr
O C++11 introduziu nullptr como um literal de tipo próprio, std::nullptr_t. Ele pode ser convertido para qualquer tipo de ponteiro, mas nunca para um inteiro ou outro tipo aritmético.
int* p = nullptr;
double* q = nullptr; // converte para double*
// int v = nullptr; // erro: não converte para inteiro
Comparando comportamentos
Sobrecarga de funções
void setup(int port);
void setup(double* sensor);
setup(NULL); // ambíguo ou seleciona setup(int)
setup(nullptr); // setup(double*)
Dedução com auto
auto h1 = NULL; // h1 é um inteiro
auto h2 = nullptr; // h2 é std::nullptr_t
Condições booleanas
bool ok1 = NULL; // compila: false
// bool ok2 = nullptr; // erro de compilação
if (nullptr) { } // OK: conversão contextual para bool
Impacto em templates
Em templates, a distinção antre NULL e nullptr fica ainda mais evidente. Como NULL pode ser deduzido como inteiro, comparações internas com nullptr podem falhar.
template<typename T>
void inspect(T value) {
if (value == nullptr) { // válido apenas para tipos de ponteiro
// ...
}
}
inspect(nullptr); // T é std::nullptr_t: OK
inspect(NULL); // T é int: comparação inválida
Cenários práticos
Inicialização após desalocação
float* samples = new float[256];
// ... uso ...
delete[] samples;
samples = nullptr; // previne uso de ponteiro pendente
Construtores que aceitam ponteiros
class Buffer {
public:
explicit Buffer(int* data);
explicit Buffer(float* data);
};
// Buffer b1(NULL); // ambíguo ou padrão errado
Buffer b2(nullptr); // ambíguo entre ponteiros, mas nunca vira int
Diretrizes de uso
| Contexto | Recomendação | Motivo |
|---|---|---|
| Projeto C puro | NULL |
nullptr não faz parte do C |
| Projeto C++ moderno | nullptr |
Segurança de tipo e clareza |
| Código C/C++ misto | Convênio da equipe | Mantenha consistência por arquivo |
Após delete/free |
nullptr |
Evita ponteiros pendentes |