Tidak semua pointer selalu punya sasaran. Fungsi pencarian bisa gagal menemukan data, opsi konfigurasi bisa tidak diisi, dan hasil pemrosesan bisa belum tersedia. Untuk situasi-situasi itu, C++ menyediakan konstanta nullptr: nilai yang secara eksplisit menyatakan “pointer ini tidak menunjuk objek apa pun”. Nilai ini sering disebut null pointer, dan memeriksa keberadaannya adalah pola pemrograman yang kita pakai hampir setiap hari. Pada Chapter ini kita membahas cara memakai nullptr, mengapa ia menggantikan makro lama NULL, dan satu aturan yang tidak bisa ditawar: nullptr tidak boleh di-dereference.
Memakai nullptr dan Memeriksanya #
Pointer yang diisi nullptr berarti kosong; pointer yang diisi alamat berarti terisi. Pemeriksaannya memakai perbandingan biasa, dan C++ juga mengizinkan bentuk ringkasnya karena pointer secara langsung bisa dievaluasi sebagai kondisi.
#include <iostream>
int main() {
int* p = nullptr; // pointer kosong: tidak menunjuk objek mana pun
if (p == nullptr) {
std::cout << "p belum menunjuk variabel mana pun\n";
}
int nilai = 77;
p = &nilai;
if (p) { // gaya ringkas: "p bukan nullptr"
std::cout << "p menunjuk nilai: " << *p << "\n";
}
p = nullptr;
if (!p) { // gaya ringkas: "p kosong"
std::cout << "p kembali kosong\n";
}
std::cout << "sizeof(nullptr) : " << sizeof(nullptr) << " byte\n";
return 0;
}Output yang Dihasilkan:
p belum menunjuk variabel mana pun
p menunjuk nilai: 77
p kembali kosong
sizeof(nullptr) : 8 byteYang perlu kita catat dari program di atas:
- Baris 6 (
int* p = nullptr;): deklarasi pointer yang jujur — sejak awal dinyatakan belum menunjuk apa-apa, bukan dibiarkan berisi alamat sampah. - Baris 8-10 (
p == nullptr): perbandingan pointer dengannullptrmenghasilkanbool. Bentuk paling eksplisit dan paling disarankan untuk dibaca pemula. - Baris 16 dan 21 (
if (p)danif (!p)): kondisi bernilai pointer dievaluasi sebagai true bila pointer terisi (bukan null) dan false bila kosong. Gaya ini lazim di kode profesional, jadi kita perlu mengenalinya. - Baris 23 (
sizeof(nullptr)):nullptrbertipe pointer null (std::nullptr_t), sehingga ukurannya sama dengan ukuran pointer lain, yaitu 8 byte pada platform 64-bit kita.
nullptr versus NULL #
Sebelum C++11, kekosongan pointer dinyatakan dengan makro NULL dari header <cstddef> — warisan bahasa C yang mengembang (expand) menjadi bilangan 0. Karena NULL sebenarnya adalah bilangan bulat, compiler tidak bisa membedakannya dari int biasa pada situasi tertentu. Masalah paling terkena muncul bersama function overloading:
#include <cstddef>
void cetak(int x) { std::cout << "int\n"; }
void cetak(int* p) { std::cout << "pointer\n"; }
int main() {
cetak(nullptr); // jelas: memilih cetak(int*)
cetak(NULL); // bermasalah di g++ 14.2
}error: call of overloaded 'cetak(NULL)' is ambiguous
note: candidate: 'void cetak(int)'
note: candidate: 'void cetak(int*)'cetak(nullptr) diterima tanpa ragu karena nullptr bertipe pointer null, bukan bilangan bulat, sehingga satu-satunya kandidat yang cocok adalah cetak(int*). Sebaliknya cetak(NULL) ambigu: NULL berupa bilangan 0 yang secara teori cocok dengan kedua overload. Contoh lain kelemahan NULL: bila ada fungsi proses(int nilai), panggilan proses(NULL) lolos compiler dan mengirim 0 — padahal maksud programmer mungkin mengirim pointer. nullptr menutup celah semacam ini karena tidak bisa diubah menjadi int secara implisit. Kesimpulannya tegas: di kode C++ modern, selalu pakai nullptr; NULL hanya kita kenali agar tidak bingung membaca kode lama.
Dereference nullptr Adalah Undefined Behavior #
Pointer kosong itu sah untuk diperiksa, disalin, dan dikirim ke fungsi — tetapi tidak sah untuk di-dereference:
int* p = nullptr;
int v = *p; // UNDEFINED BEHAVIOR: tidak ada objek di alamat 0
Standar C++ tidak mendefinisikan apa pun yang terjadi saat baris itu dieksekusi. Pada praktiknya, kebanyakan sistem operasi menghentikan program dengan pesan seperti segmentation fault karena alamat rendah dilindungi dari akses, tetapi perilaku tersebut bukan jaminan bahasa — compiler berhak melakukan apa saja, termasuk menghapus pemeriksaan di sekitarnya. Karena itulah pemeriksaan if (p != nullptr) sebelum dereference adalah kebiasaan yang tidak boleh dilewati, kecuali kita sudah yakin pointer itu terisi.
Null pointer kini sudah kita kuasai. Selanjutnya kita sambungkan dua konsep besar yang sudah kita punya: array dan pointer. Keduanya terhubung begitu erat sehingga banyak pemula menganggapnya sama — dan mengetahui batas persisnya adalah bekal penting sebelum masuk ke pointer arithmetic.
Referensi: cppreference — nullptr , cppreference — NULL , cppreference — pointer .