İf (pointer! = NULL) yerine if (pointer) kullanabilir miyim?


171

Bir işaretçiyi NULLbasitçe yazarak kontrol etmemek güvenli mi if(pointer)yoksa kullanmam gerekiyor if(pointer != NULL)mu?


14
Gerçek şu ki, açık bir kontrol kullanacaksanız, 0veya testini yapmak kadar etkili ve sıklıkla tercih edilir nullptr. ( NULLbir C'ism'dir ve bir başlık dosyası da gerektirir.)
cHao

5
@danijar Modern C ++ 'da nullptr kullanabilirsiniz.
SurvivalMachine

9
@cHao "C ile uyumluluk hedefliyor" un amacı nerededir?
qdii

5
@danijar: Evet, bu uygulamadan NULLC ++ ' da kullanmamalısınız , çünkü NULLbelirsiz davranışlar verebilecek uygulamaya bağlı makrodur.
Alok Kaydet

3
Bu 'eğer' durum olmasa da, siz "NULL" ve "0" C ++ işaretçileri için kaçınmalısınız neden olarak bu ideone canlı demo görmek ideone.com/tbvXNs
kfsone

Yanıtlar:


198

Yapabilirsin; null işaretçisi örtük olarak boole false değerine, null olmayan işaretçiler true değerine dönüştürülür. C ++ 11 standardından, Boole Dönüşümleri bölümü :

Aritmetik, kodlanmamış numaralandırma, işaretçi veya işaretçi ile üye türünün bir ön değeri, bir tür ön değerine dönüştürülebilir bool. Sıfır değeri, boş işaretçi değeri veya boş üye işaretçi değeri dönüştürülür false; başka bir değere dönüştürülür true . Bir tür ön değeri, bir tür ön değerine std::nullptr_t dönüştürülebilir bool ; elde edilen değer false .


42

Evet yapabilirdin.

  • Boş bir işaretçi dolaylı olarak yanlış değerine dönüştürülür
  • boş olmayan bir işaretçi true değerine dönüştürülür.

Bu, Boole dönüşüm yan tümcesinde yer alan C ++ standart dönüşümünün bir parçasıdır :

§ 4.12 Boole dönüşümleri

Aritmetik, kodlanmamış numaralandırma, işaretçi ya da işaretçi ile üye türünün bir ön değeri, bool türünün bir ön değerine dönüştürülebilir. Sıfır değeri, null işaretçi değeri veya null üye işaretçi değeri false değerine dönüştürülür; diğer herhangi bir değer true değerine dönüştürülür. Std :: nullptr_t türünün bir ön değeri, bool türünün bir ön değerine dönüştürülebilir; sonuçta ortaya çıkan değer yanlıştır.


30

Evet yapabilirsin. Aslında kullanmayı tercih ediyorum if(pointer)çünkü alıştıktan sonra okumak ve yazmak daha kolay.

Ayrıca nullptrtercih edilen C ++ 11 tanıtıldı NULL.


10
İşaretçi boole ifadesi değildir. Örtük olarak dönüştürülür. Bu dönüşümü hatırlamak zorunda olduğunuzda okumak daha iyi ise anlamak sizin görüşünüzdür. Sadece bir tür kodlama tarzı.
harper

7
@harper Bunun bir kodlama stili olduğunu söyleyebilirsiniz. Ama aynı mantığı uygulayabilirsiniz if(som_integer)vs if(some_integer != 0)tamsayılar da boolean doğru değildir çünkü? Kaçınmayı 0veya NULLbir if ifadesinde tercih ederim .
Yu Hao

13
Bunun bir kodlama tarzı meselesi olduğunu kabul ediyorum. if (pointer)Kendimi tercih etmeye geldim , ama if (ptr != nullptr)benim için gayet meşru görünüyor. Öte yandan, ekibimde yazan birini görürsem, if (some_integer)onları değiştirmesini isterdim if (some_integer != 0). Ancak, bu benim tarafımda nispeten keyfi bir tercih değil gibi davranmayacağım - sadece işaretçileri ve tamsayıları aynı şekilde tedavi etmemeyi tercih ederim.
Joel

1
@YuHao Kod tarzı olduğu için "tercih edilir" değil, "tercih ederim" ifadesini verdim.
harper

5
@ franji1 O zaman nasıl if(isReady) if(filePtr) if(serviceNo)? Kötü değişken isimlerini bilerek yapmak bu durumda pek bir şey ifade etmez. Her neyse, zaten fikrini aldım ve anladım, ama kendi kodlama tarzımı kendim kullanmakta ısrar edebilirim, tamam mı?
Yu Hao

13

Soru cevaplandı, ama puanlarımı eklemek istiyorum.

Her zaman if(pointer)yerine if(pointer != NULL)ve if(!pointer)yerine her zaman tercih edeceğim if(pointer == NULL):

  • Basit, küçük
  • Daha az şansı Ben eşitlik onay operatörü yanlış yazılmış ise varsayalım, bir arabası kod yazmak için ==birlikte =
    if(pointer == NULL)yanlış yazılmış olabilir if(pointer = NULL)bunu önlemek olacaktır Yani, iyi adildir if(pointer).
    (Ben de bir cevapta Yoda durumu önerdim , ama bu farklı bir konu)

  • Benzer şekilde while (node != NULL && node->data == key), sadece while (node && node->data == key)benim için daha belirgin olduğunu yazacağım (kısa devre kullandığını gösterir).

  • (aptalca bir sebep olabilir) Çünkü NULL bir makrodur, varsayalım ki bir tanesi yanlışlıkla başka bir değerle yeniden tanımlar.

6
== yerine == kullanmak neredeyse her zaman bir derleyici uyarısı oluşturur, insanların kullanmadığı günlerde (NULL == ptr)
paulm

@paulm sadece bu noktayı Yoda Koşulu olarak ekledim, bazı insanlar daha az okunabilir olarak sevmiyorlar.
Grijesh Chauhan

2
(boolean expression)? true : falsetamamen anlamsız. Ya sentezleme değerlendirir trueveya false; "doğruysa, bana doğru ver, eğer yanlışsa, bana yanlış ver" der. Kısacası: Bu tamamen boole ifadesinin kendisine eşdeğerdir. Bunun node == NULLbir boole ifadesi olduğuna dikkat edin . BTW, iki uygulamanız birbirinin tam tersini döndürür. Ya !=ilkinde ister !ikincisinde sadece birini istersiniz .
celtschk

BTW, =yerine karşı olası bir koruma ==değişkenlerinizi constmümkün olduğunca yapmaktır . Örneğin, işlevinizi olarak tanımlayabilirsiniz isEmnpy(node* const head) { ... }ve sonra node = NULLbunun yerine yanlışlıkla yazdıysanız derleyici işlevi derlemeyi reddeder node == NULL. Tabii ki bu sadece gerçekten değiştirmeniz gerekmeyen değişkenler için geçerlidir.
celtschk

2
Akıllı işaretçiyi sınıfları olması nedeniyle T* get() constyerine operator T*() constörtülü dönüşüm önlemek için. Ancak bir operator bool() const.
StellarVortex

13

NULL için açıkça kontrol etmek derleyiciye ne yapmaya çalıştığınıza dair bir ipucu verebilir, ergo daha az hataya eğilimli olmaya yol açar.

resim açıklamasını buraya girin


8

Evet yapabilirsin. Değerleri sıfırlarla örtük olarak karşılaştırma yeteneği C'den devralınmıştır ve tüm C ++ sürümlerinde vardır. if (!pointer)NULL için işaretçileri kontrol etmek için de kullanabilirsiniz .


2

Boş göstericiler için ilgili kullanım durumları

  • Henüz var olmayan veya henüz bağlanmamış olan daha derin bir ağaç düğümü gibi bir şeye yönlendirme. Bu, özel bir sınıfta her zaman yakından kapsamanız gereken bir şeydir, bu nedenle okunabilirlik veya kısalık burada bir sorun değildir.
  • Dinamik yayınlar. Belirli bir türetilmiş sınıfa bir temel sınıf işaretçisi atamak (yine kaçınmaya çalışmanız gereken, ancak bazen gerekli bulabilecek bir şey) her zaman başarılı olur, ancak türetilmiş sınıf eşleşmezse boş gösterici ile sonuçlanır. Bunu kontrol etmenin bir yolu

    Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
    if(derived_ptr != nullptr) { ... }

    (veya tercihen, auto derived_ptr = ...). Şimdi, bu kötü, çünkü (muhtemelen geçersiz, yani boş) türetilmiş işaretçiyi güvenlik koruma ifbloğunun kapsamı dışında bırakır . C ++ bir ifkoşul içinde boole dönüştürülebilir değişkenleri tanıtmanıza izin verdiği için bu gerekli değildir :

    if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }

    ki bu sadece daha kısa ve kapsam açısından güvenli değil, aynı zamanda niyetinde çok daha açık: ayrı bir if-koşulunda null olup olmadığını kontrol ettiğinizde, okuyucu "tamam, bu yüzden derived_ptrburada null olmamalıdır ... boş mu? " Tek satırlık sürümü çok açık söylüyor Oysa "güvenle döküm eğer base_ptrüzere Derived*, daha sonra için kullanabilirsiniz ...".

    Aynı şey, bir işaretçi döndüren diğer olası başarısızlık işlemleri için de işe yarar, ancak IMO genellikle bundan kaçınmalısınız: boost::optionalişaretçilerden ziyade muhtemelen başarısız işlemlerin sonuçları için "kapsayıcı" gibi bir şey kullanmak daha iyidir.

Boş göstericilerle ana kullanım durumu her zaman örtük-dökme tarzı bir varyasyonu olarak yazılmalıdır Yani, ben tutarlılık nedenleriyle 's iyi derdim hep ben savunmak istiyorum yani bu stili kullanan if(ptr)üzerinde if(ptr!=nullptr).


Korkarım ki bir reklamla bitmeliyim: if(auto bla = ...)sözdizimi aslında bu tür sorunların gerçek çözümüne biraz hantal bir yaklaşımdır : desen eşleştirme . Neden önce bir eylemi zorlarsınız (bir işaretçi yapmak gibi) ve sonra bir hata olabileceğini düşünürsünüz ... Yani, saçma, değil mi? Sanki biraz yiyecek var ve çorba yapmak istiyorsun. Yumuşak bir sebze olursa, suyu çıkarmak için görevinize asistanınıza verirsiniz. Önce ona bakmıyorsun. Patatesiniz varsa, hala yardımcınıza verirsiniz ama başarısızlık notuyla yüzünüze tokatlar. Ah, zorunlu programlama!

Çok daha iyi: Karşılaşabileceğiniz tüm vakaları hemen düşünün. Sonra buna göre hareket edin. 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 ayrıca gerçekten ciddi bir başarısızlık olasılığı olduğunda (ve bir sürü başka şey için) özel araçlara sahiptir: monadlar. Ama bu onları açıklamak için bir yer değil.

⟨/ Advert⟩


1
Bu bitmez tükenmez şapta soruyu cevaplayan tek bir cümle görebiliyorum.
Lorne Marquis

@EJP: Eğer soruyu tam anlamıyla alırsanız (" kullanabilir miyim"), o zaman hiç açıkça cevaplanmaz (cevap basitçe "evet" tir ). OP'nin neden kullanmaktan ziyade neden kullanması gerektiğine dair uygun nedenler vermeye çalıştım , ki bunu söylemek için biraz daha var. if(ptr)if(ptr != nullptr)
leftaroundabout

1

Evet tabi ki! aslında, eğer (pointer) yazmak, (pointer! = NULL) yerine yazmanın daha kolay bir yoludur çünkü: 1. hata ayıklamak kolaydır 2. anlaşılması kolaydır 3. yanlışlıkla ise, NULL değeri tanımlanırsa, o zaman kod çökmez




-1

Evet, bunu her zaman yapabilirsiniz 'EĞER' koşulu yalnızca içindeki koşul gerçekleştiğinde değerlendirilir. C'nin bir boole dönüş türü yoktur ve bu nedenle koşul doğru olduğunda sıfırdan farklı bir değer döndürürken, 'IF' içindeki koşul yanlış olduğunda 0 değerini döndürür. Varsayılan olarak döndürülen sıfır olmayan değer 1'dir. Bu nedenle, her zaman ikincisini tercih ederken, kodu yazmanın her iki yolu da doğrudur.


1
Doğru hatırlamıyorsam varsayılan olarak sıfır olmayan değer tanımsızdır.
Lorne Marquis

-1

If-ifadeniz şu şekilde yeniden yazılabilirse , genel bir kural olarak düşünüyorum

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

hiçbir uyarıya neden olmayacak şekilde if ifadesi için THAT tercih edilmelidir . ( İşaretçilerden bağımsız olarak bir C ++ 'a eski bir C BOOL( #define BOOL int) atadığımda uyarı aldığımı biliyorum bool.)


-1

"Güvenli mi..?" , dil standardı ve oluşturulan kod hakkında bir sorudur.

"İyi bir uygulama mı?" ifadenin, herhangi bir keyfi insan okuyucu tarafından ifadenin ne kadar iyi anlaşıldığı sorusudur. Bu soruyu soruyorsanız, "güvenli" sürümün gelecekteki okuyucular ve yazarlar için daha az net olduğu anlaşılmaktadır.


Niyetim güvenli olup olmadığını sormaktı. Bu ifadeyi kullandım. Ancak, burada yazdıklarınız sorunun cevabı değildir. Bunun yerine, sorunun altındaki bir yorum olmalıdır. Daha sonra yanıtı silebilir ve sorunun altına yorum ekleyebilirsiniz.
danijar

@danijar StackOverflow'da yeni olduğunuzu ve 'Yorum' bölümünü başarılı bir şekilde aradığınızı hatırlamıyor musunuz? Şöhreti 7 olan biri bunu yapamaz.
Broxzier

@JimBalter Başkalarının bunu yaptığını görebildiğiniz için çok kafa karıştırıcı. SO'ya yeni geldiğimde birisi bunu yaptığım için beni suçladı.
Broxzier

@JimBalter Katliam ve çalmıyorum. Ben anlatıyordu danijar o Fred Mitchell yeni bir kullanıcı oldu ve yayınla yapamadı.
Broxzier

@JimBalter Bugün başladığınız yer. Ayrıca bunun yerine anlamayan sizsiniz. Bu yorum sadece bunun karıştırılmasını destekliyor.
Broxzier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.