Dapatkah saya menggunakan if (pointer) alih-alih if (pointer! = NULL)?

171

Apakah aman untuk memeriksa pointer ke tidak NULLdengan hanya menulis if(pointer)atau harus saya gunakan if(pointer != NULL)?

danijar
sumber
13
Kebenarannya adalah, jika Anda akan menggunakan pemeriksaan eksplisit, itu sama efektifnya - dan sering lebih disukai - untuk diuji terhadap 0atau nullptr. ( NULLadalah C'ism, dan membutuhkan termasuk file header.)
cHao
5
@danijar Anda bisa menggunakan nullptr di C ++ modern.
SurvivalMachine
9
@ cHao Di mana titik "bertujuan untuk kompatibilitas dengan C"?
qdii
5
@danijar: Ya, Anda tidak boleh menggunakan NULLdalam C ++ mulai dari ini karena NULLini adalah implementasi yang bergantung makro yang mungkin memberi Anda perilaku ambigu.
Alok Simpan
3
Meskipun ini bukan 'jika' kasus, lihat ideone ini live demo mengapa Anda harus menghindari "NULL" dan "0" untuk pointer di C ++: ideone.com/tbvXNs
kfsone

Jawaban:

198

Kamu bisa; pointer nol secara implisit dikonversi menjadi boolean false sementara pointer non-null dikonversi menjadi true. Dari standar C ++ 11, bagian tentang Konversi Boolean:

Nilai awal aritmatika, penghitungan yang tidak dicentang, penunjuk, atau penunjuk ke tipe anggota dapat dikonversi ke nilai jenis sebelumnya bool. Nilai nol, nilai pointer nol, atau nilai pointer anggota null dikonversi menjadi false; nilai lain dikonversi ke true . Prvalue tipe std::nullptr_t dapat dikonversi ke prvalue tipe bool ; nilai yang dihasilkan adalah false .

Joni
sumber
42

Ya kamu bisa.

  • Pointer null dikonversi menjadi false secara implisit
  • pointer non-null dikonversi menjadi true.

Ini adalah bagian dari konversi standar C ++, yang termasuk dalam klausa konversi Boolean :

§ 4.12 Konversi Boolean

Nilai awal aritmatika, penghitungan yang tidak dicentang, penunjuk , atau penunjuk ke tipe anggota dapat dikonversi ke nilai awal tipe bool. Nilai nol, nilai pointer nol, atau nilai pointer anggota null dikonversi menjadi false; nilai lain dikonversi menjadi true. Prvalue tipe std :: nullptr_t dapat dikonversi ke prvalue tipe bool; nilai yang dihasilkan salah.

billz
sumber
29

Ya kamu bisa. Bahkan, saya lebih suka menggunakan if(pointer)karena lebih mudah untuk membaca dan menulis begitu Anda terbiasa.

Perhatikan juga bahwa C ++ 11 yang diperkenalkan nullptrlebih disukai NULL.

Yu Hao
sumber
10
Pointer bukan ekspresi boolean. Itu dikonversi secara implisit. Jika lebih baik membaca ketika Anda harus mengingat konversi ini untuk memahami adalah pendapat Anda. Itu hanya satu jenis gaya pengkodean.
pemain harpa
7
@ Harper Anda bisa mengatakan itu gaya pengkodean. Tetapi Anda dapat menerapkan logika yang sama untuk if(som_integer)vs if(some_integer != 0)karena bilangan bulat juga bukan boolean, bukan? Saya lebih suka menghindari 0atau NULLdalam pernyataan if.
Yu Hao
13
Saya setuju itu hanya masalah gaya pengkodean. Saya datang untuk lebih menyukai if (pointer)diri saya sendiri, tetapi if (ptr != nullptr)tampaknya sangat sah bagi saya. Di sisi lain, jika saya melihat seseorang di tim saya yang menulis if (some_integer)saya akan membuat mereka mengubahnya if (some_integer != 0). Namun, saya tidak akan berpura-pura itu bukan preferensi yang relatif sewenang-wenang di pihak saya - saya hanya memilih untuk tidak memperlakukan pointer dan bilangan bulat yang sama.
Joel
1
@YuHao Dan karena itu gaya kode saya tidak akan menyatakan "itu lebih disukai" tetapi "Saya lebih suka".
pemain harpa
5
@ franji1 Lalu bagaimana if(isReady) if(filePtr) if(serviceNo)? Membuat nama variabel yang buruk dengan sengaja tidak banyak berarti dalam kasus ini. Pokoknya saya sudah mengerti maksud Anda dan memahaminya, tapi saya bisa bersikeras menggunakan gaya pengkodean saya sendiri, oke?
Yu Hao
13

Pertanyaan dijawab, tetapi saya ingin menambahkan poin saya.

Saya akan selalu lebih suka if(pointer)daripada if(pointer != NULL)dan if(!pointer)bukannya if(pointer == NULL):

  • Sederhana, kecil
  • Kurang kesempatan untuk menulis kode kereta, kira jika aku salah eja Operator cek kesetaraan ==dengan =
    if(pointer == NULL)dapat salah eja if(pointer = NULL)Jadi saya akan menghindarinya, terbaik hanya if(pointer).
    (Saya juga menyarankan beberapa kondisi Yoda dalam satu jawaban , tapi itu masalah lain)

  • Demikian pula untuk while (node != NULL && node->data == key), saya hanya akan menulis while (node && node->data == key)yang lebih jelas bagi saya (menunjukkan bahwa menggunakan korsleting).

  • (mungkin alasan bodoh) Karena NULL adalah makro, jika seandainya seseorang mendefinisikan ulang secara tidak sengaja dengan nilai lain.
Grijesh Chauhan
sumber
6
Menggunakan = bukannya == hampir selalu menghasilkan peringatan kompiler, di hari-hari ketika itu tidak digunakan orang jika (NULL == ptr)
paulm
@ paulm bahwa saya baru saja menambahkan titik ini yang disebut Kondisi Yoda beberapa orang tidak menyukainya karena kurang dapat dibaca.
Grijesh Chauhan
2
(boolean expression)? true : falsesama sekali tidak ada gunanya. Ekspresi mengevaluasi ke trueatau ke false; apa yang Anda katakan adalah "jika itu benar, beri aku benar, jika itu salah, beri aku salah". Singkatnya: Ini sepenuhnya sama dengan ekspresi boolean itu sendiri. Perhatikan bahwa node == NULLini adalah ekspresi boolean. BTW, dua implementasi Anda menghasilkan kebalikan dari satu sama lain. Entah Anda ingin !=yang pertama, atau hanya satu !yang kedua.
celtschk
BTW, satu kemungkinan perlindungan terhadap =bukan ==membuat variabel Anda constkapan pun memungkinkan. Misalnya, Anda bisa mendefinisikan fungsi Anda sebagai isEmnpy(node* const head) { ... }, dan kemudian compiler akan menolak untuk mengkompilasi jika Anda secara tidak sengaja menulis node = NULLbukan node == NULL. Tentu saja itu hanya berfungsi untuk variabel yang Anda benar-benar tidak perlu ubah.
celtschk
2
Karena kelas smart pointer memiliki T* get() constalih - alih operator T*() constmenghindari konversi implisit. Namun mereka memiliki operator bool() const.
StellarVortex
13

Memeriksa secara eksplisit untuk NULL dapat memberikan petunjuk kepada kompiler tentang apa yang Anda coba lakukan, ergo mengarah ke yang kurang rawan kesalahan.

masukkan deskripsi gambar di sini

Minqi Pan
sumber
8

Ya kamu bisa. Kemampuan untuk membandingkan nilai dengan nol secara implisit telah diwarisi dari C, dan ada di semua versi C ++. Anda juga dapat menggunakan if (!pointer)untuk memeriksa pointer untuk NULL.

dasblinkenlight
sumber
2

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 ifruang 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_ptrtidak boleh nol di sini ... yah, mengapa itu nol? " Sedangkan versi satu baris kata yang sangat jelas "jika Anda dapat dengan aman dilemparkan base_ptrke 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::optionalsebagai "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⟩

leftaroundabout
sumber
1
Saya hanya dapat melihat satu kalimat dalam screed yang tak berkesudahan ini yang sebenarnya menjawab pertanyaan.
Marquis of Lorne
@ EJP: jika Anda menerima pertanyaan secara harfiah (" bisakah saya menggunakan"), maka itu tidak dijawab sama sekali secara eksplisit (jawabannya hanyalah "ya"). Saya mencoba memberikan alasan yang tepat mengapa OP sebenarnya harus menggunakan if(ptr)daripada if(ptr != nullptr), yang ada cukup banyak untuk dikatakan.
leftaroundabout
1

ya tentu saja! pada kenyataannya, menulis jika (pointer) adalah cara penulisan yang lebih nyaman daripada jika (pointer! = NULL) karena: 1. mudah untuk debug 2. mudah dimengerti 3. jika tidak sengaja, nilai NULL didefinisikan, maka kode juga tidak akan crash

Palak Jain
sumber
0

Iya. Padahal seharusnya begitu. Jika Anda bertanya-tanya apakah itu menciptakan kesalahan segmentasi , itu tidak.

darshandzend
sumber
29
Kenapa harus kamu?
qdii
0

Karena orang lain sudah menjawab dengan baik, mereka berdua dapat dipertukarkan.

Meskipun demikian, perlu disebutkan bahwa mungkin ada kasus di mana Anda mungkin ingin menggunakan pernyataan eksplisit, yaitu pointer != NULL.

Lihat juga https://stackoverflow.com/a/60891279/2463963

z3moon
sumber
-1

Ya, Anda selalu dapat melakukan ini karena kondisi 'JIKA' hanya mengevaluasi ketika kondisi di dalamnya benar. C tidak memiliki tipe pengembalian boolean dan dengan demikian mengembalikan nilai bukan nol ketika kondisi benar sementara mengembalikan 0 setiap kali kondisi di 'JIKA' ternyata salah. Nilai bukan nol yang dikembalikan secara default adalah 1. Dengan demikian, kedua cara penulisan kode sudah benar sementara saya akan selalu lebih suka yang kedua.

pengguna2280507
sumber
1
Nilai bukan nol secara default tidak ditentukan jika saya ingat dengan benar.
Marquis of Lorne
-1

Saya pikir sebagai aturan praktis, jika ekspresi if Anda dapat ditulis ulang sebagai

const bool local_predicate = *if-expression*;
if (local_predicate) ...

sedemikian rupa sehingga TIDAK menyebabkan PERINGATAN, maka ITULAH harus menjadi gaya yang disukai untuk ekspresi if . (Saya tahu saya mendapat peringatan ketika saya menetapkan C lama BOOL( #define BOOL int) ke C ++ bool, apalagi pointer.)

franji1
sumber
-1

"Apakah itu aman ..?" adalah pertanyaan tentang standar bahasa dan kode yang dihasilkan.

"Apakah ini latihan yang bagus?" adalah pertanyaan tentang seberapa baik pernyataan itu dipahami oleh setiap pembaca manusia yang sewenang-wenang dari pernyataan itu. Jika Anda mengajukan pertanyaan ini, itu menunjukkan bahwa versi "aman" kurang jelas bagi pembaca dan penulis di masa depan.

Fred Mitchell
sumber
Niat saya adalah untuk bertanya apakah itu aman. Karena itu saya menggunakan kata-kata itu. Namun, apa yang Anda tulis di sini bukanlah jawaban untuk pertanyaan itu. Sebaliknya, itu harus menjadi komentar di bawah pertanyaan. Anda dapat menghapus jawabannya dan menambahkan komentar di bawah pertanyaan itu.
danijar
@danijar Tidakkah Anda ingat ketika Anda masih baru di StackOverflow dan mencari bagian 'Komentar' tanpa hasil? Seseorang dengan 7 reputasi tidak dapat melakukan itu.
Broxzier
@ JimBalter Yang sangat membingungkan, karena Anda dapat melihat orang lain melakukannya. Ketika saya masih baru jadi SO seseorang menyalahkan saya untuk melakukan itu.
Broxzier
@ JimBalter saya tidak membunuh dan mencuri. Saya memberi tahu danijar bahwa Fred Mitchell adalah pengguna baru dan tidak dapat memposting komentar.
Broxzier
@ JimBalter Yang Anda mulai hari ini. Anda juga yang tidak mengerti. Komentar itu hanya mendukung yang membingungkan ini.
Broxzier