Dua cara merujuk sesuatu
Kamu sudah mengenal pointer: variabel yang menyimpan alamat dan memungkinkan kamu menjangkau objek yang tinggal di sana. Reference adalah alat lain yang diberikan C++ untuk bekerja secara tidak langsung dengan objek yang sudah ada. Keduanya cukup mirip sampai pemula sering bingung harus memilih yang mana, jadi halaman ini membandingkan keduanya berdampingan.
Versi singkatnya: reference adalah alias. Begitu int& r = x; dijalankan, r adalah x: objek yang sama, nama yang berbeda. Pointer adalah objek terpisah yang kebetulan menyimpan alamat objek lain. Satu perbedaan itu menentukan semua hal lainnya.
Reference adalah alias
Reference harus diikat ke sebuah objek saat dibuat, dan sejak itu setiap pemakaian reference menyentuh objek aslinya.
Perhatikan bahwa tidak ada * untuk dereference dan tidak ada & untuk "mengambil alamat" di tempat pemakaiannya. Kamu membaca dan menulis alias persis seperti int biasa. & pada int& alias adalah bagian dari tipe, bukan operator address-of.
Di mana perbedaannya
Perilaku di bawah ini adalah alasan kedua alat itu ada. Inilah tabel yang perlu kamu hafal.
// reference pointer
// must be initialized? yes no (but should be)
// can be null? no yes (nullptr)
// can be reseated? no yes
// pointer arithmetic? no yes
// syntax to use it just the name *p or p->member
// taking address &ref == &original &p is the pointer's own address
Dua di antaranya paling sering menjebak. Pertama, reference tidak pernah bisa diarahkan ulang. Mengisi nilai ke reference berarti menyalin nilai ke dalam objek yang dirujuknya, bukan mengarahkan reference itu ke sesuatu yang baru.
Sebaliknya, pointer bebas menunjuk ke tempat lain kapan saja:
Kedua, reference tidak pernah boleh null, sedangkan pointer bisa. Itu artinya "tidak ada nilai" bisa dinyatakan dengan pointer tapi tidak dengan reference, sifat yang akan sangat sering kamu andalkan.
Memilih untuk parameter fungsi
Di sinilah pilihan itu paling sering muncul. Saat sebuah fungsi perlu membaca atau mengubah objek milik pemanggilnya, keduanya bisa dipakai, tapi masing-masing menyampaikan maksud yang berbeda.
Versi reference (addTax(cart)) tidak mungkin dipanggil dengan "tidak ada apa-apa", jadi di dalam fungsi kamu tidak perlu mengecek null: objeknya dijamin ada. Versi pointer (applyDiscount(&cart)) menunjukkan di tempat pemanggilan, lewat &, bahwa argumennya mungkin diubah, dan memungkinkan pemanggil mengirim nullptr yang berarti "tidak berlaku". Pilih yang jaminannya cocok dengan fungsimu.
Untuk parameter baca saja yang tipenya besar, pilihan yang lazim adalah const T&: cara ini menghindari penyalinan dan berjanji tidak akan mengubah apa pun. Lihat halaman parameter fungsi untuk pembahasan lebih lanjut tentang pass by value vs pass by reference.
Aturan praktis sederhana
Kalau ragu, pakai reference sebagai default dan baru beralih ke pointer saat kamu butuh kemampuan yang tidak dimiliki reference:
- Pakai reference kalau objeknya selalu ada dan identitasnya tidak pernah berubah. Ini kasus umum untuk parameter fungsi dan alias.
- Pakai pointer kalau salah satu hal ini benar:
- "Tidak ada apa-apa" adalah keadaan yang sah (argumen opsional, pencarian yang mungkin tidak menemukan hasil): pointer bisa bernilai
nullptr. - Kamu perlu menunjuk ke objek yang berbeda seiring waktu: pointer bisa diarahkan ulang.
- Kamu mengelola memori heap yang nanti akan di-
delete(atau, lebih baik lagi, smart pointer), atau menelusuri array dengan aritmatika pointer.
- "Tidak ada apa-apa" adalah keadaan yang sah (argumen opsional, pencarian yang mungkin tidak menemukan hasil): pointer bisa bernilai
Kalau tidak ada yang berlaku, reference adalah pilihan yang lebih bersih dan aman, karena compiler memastikan "selalu sah, tidak pernah diarahkan ulang" untukmu.
Kesalahan umum yang perlu dihindari
- Mengira
ref = otherakan mengarahkan ulang. Pernyataan itu justru mengisi nilai ke objek yang dirujuk. Reference terikat seumur hidup; kalau kamu butuh pengarahan ulang, pakai pointer. - Mengembalikan reference (atau pointer) ke variabel lokal.
int& f() { int x = 5; return x; }mengembalikan dangling reference:xmati saatfselesai, dan memakai hasilnya adalah undefined behavior. Jebakan yang sama berlaku untuk pointer (return &x;). - Memalsukan "reference null". Menulis
int& r = *p;saatpbernilainullptradalah undefined behavior begitu dereference terjadi, bukan reference "kosong" yang aman. Nyatakan sifat opsional dengan pointer ataustd::optional. - Memakai pointer karena kebiasaan. Kalau argumennya selalu ada dan tidak akan pernah diarahkan ulang, reference menghilangkan seluruh jenis pengecekan null dan crash. Jangan membayar kemampuan yang tidak kamu pakai.
Berikutnya: memori dinamis
Sejauh ini setiap objek yang kamu rujuk atau tunjuk dibuat secara otomatis di stack. Halaman berikutnya, memori dinamis, membahas new dan delete: meminta memori ke sistem operasi saat runtime, kenapa pointer (bukan reference) yang memilikinya, dan bagaimana lupa membebaskannya menyebabkan memory leak.
Pertanyaan yang sering diajukan
Apa perbedaan reference dan pointer di C++?
Reference adalah alias untuk objek yang sudah ada: ia harus diinisialisasi, tidak pernah bisa null, dan setelahnya tidak bisa diarahkan ke objek lain. Pointer adalah variabel terpisah yang menyimpan alamat: ia bisa null, bisa diarahkan ulang ke tempat lain, dan mendukung aritmatika pointer. Pakai sintaks & untuk reference dan */-> untuk pointer.
Kapan sebaiknya memakai pointer alih-alih reference di C++?
Pakai pointer kalau "tidak ada apa-apa" adalah keadaan yang sah (argumen opsional, hasil pencarian yang tidak ketemu), kalau kamu perlu mengarahkannya ulang ke objek yang berbeda seiring waktu, atau kalau kamu memiliki memori heap yang nanti akan di-delete. Pakai reference kalau objeknya selalu ada dan identitasnya tidak pernah berubah, dan itu mencakup sebagian besar parameter fungsi.
Bisakah reference bernilai null di C++?
Tidak. Reference yang sah selalu merujuk ke objek sungguhan, jadi kamu tidak pernah perlu mengecek null. Kalau kamu membuat reference dari null pointer yang di-dereference (int& r = *p; dengan p bernilai null), yang kamu dapat adalah undefined behavior, bukan reference null. Kalau kamu perlu menyatakan "mungkin tidak ada", pakai pointer atau std::optional.