Kasus penggunaan yang relevan untuk null pointer adalah
- Pengalihan ke sesuatu seperti simpul pohon yang lebih dalam, yang mungkin belum ada atau belum ditautkan. Itu adalah sesuatu yang harus selalu Anda tutupi dengan ketat di kelas khusus, jadi keterbacaan atau keringkasan tidak menjadi masalah besar di sini.
Gips dinamis. Melemparkan pointer kelas dasar ke kelas turunan tertentu (sesuatu yang harus Anda coba hindari lagi, tetapi kadang-kadang mungkin perlu) selalu berhasil, tetapi menghasilkan pointer nol jika kelas turunan tidak cocok. Salah satu cara untuk memeriksanya adalah
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != nullptr) { ... }
(atau, lebih disukai, auto derived_ptr = ...
). Sekarang, ini buruk, karena meninggalkan pointer yang diturunkan (kemungkinan tidak valid, yaitu null) di luar if
ruang lingkup blok pengaman . Ini tidak perlu, karena C ++ memungkinkan Anda untuk memperkenalkan variabel boolean-convertable di dalam if
-condition :
if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
yang tidak hanya lebih pendek dan lingkup-aman, itu juga jauh lebih jelas dalam tujuannya: ketika Anda memeriksa nol dalam kondisi-if terpisah, pembaca bertanya-tanya "ok, jadi derived_ptr
tidak boleh nol di sini ... yah, mengapa itu nol? " Sedangkan versi satu baris kata yang sangat jelas "jika Anda dapat dengan aman dilemparkan base_ptr
ke Derived*
, kemudian menggunakannya untuk ...".
Hal yang sama juga berfungsi untuk operasi kemungkinan-gagal lainnya yang mengembalikan pointer, meskipun IMO Anda biasanya harus menghindari ini: lebih baik menggunakan sesuatu seperti boost::optional
sebagai "wadah" untuk hasil operasi yang mungkin gagal, daripada pointer.
Jadi, jika use case utama untuk null pointer harus selalu ditulis dalam variasi gaya implisit-cast, saya akan mengatakan itu baik untuk alasan konsistensi untuk selalu menggunakan gaya ini, yaitu saya akan mengadvokasi untuk if(ptr)
lebih if(ptr!=nullptr)
.
Saya khawatir saya harus mengakhiri dengan iklan: if(auto bla = ...)
sintaks sebenarnya hanya pendekatan yang sedikit rumit untuk solusi nyata untuk masalah seperti: pencocokan pola . Mengapa Anda pertama kali memaksakan beberapa tindakan (seperti melemparkan pointer) dan kemudian mempertimbangkan bahwa mungkin ada kegagalan ... Maksud saya, ini konyol, bukan? Ini seperti, Anda memiliki beberapa bahan makanan dan ingin membuat sup. Anda memberikannya kepada asisten Anda dengan tugas untuk mengekstrak jus, jika itu adalah sayuran lunak. Anda tidak pertama-tama melihatnya. Ketika Anda memiliki kentang, Anda masih memberikannya kepada asisten Anda tetapi mereka menamparnya kembali di wajah Anda dengan catatan kegagalan. Ah, pemrograman imperatif!
Jauh lebih baik: segera pertimbangkan semua kasus yang mungkin Anda temui. Kemudian bertindak sesuai. Haskell:
makeSoupOf :: Foodstuff -> Liquid
makeSoupOf p@(Potato{..}) = mash (boil p) <> water
makeSoupOf vegetable
| isSoft vegetable = squeeze vegetable <> salt
makeSoupOf stuff = boil (throwIn (water<>salt) stuff)
Haskell juga memiliki alat khusus untuk ketika benar-benar ada kemungkinan kegagalan yang serius (dan juga untuk banyak hal lainnya): monads. Tapi ini bukan tempat untuk menjelaskannya.
⟨/iklan⟩
0
ataunullptr
. (NULL
adalah C'ism, dan membutuhkan termasuk file header.)