NULL işaretçisini silmek güvenli midir?


299

NULL işaretçisini silmek güvenli midir?

Ve bu iyi bir kodlama tarzı mı?


21
İyi uygulama, tek bir çağrı yapmadan C ++ programları yazmaktır delete. Kullanım de ray yerine. Yani kullanımı olup std::vector<T> v(100);yerine T* p = new T[100];, akıllı gibi işaretçileri kullanmak unique_ptr<T>ve shared_ptr<T>vb silme o icabına yerine ham işaretçileri
fredoverflow

8
sayesinde make_shared(c ++ 11) ve make_unique(c ++ 14) program içermelidir sıfır ait newvedelete
sp2danny

2
Yeni / silme gerektiren bazı nadir durumlar olabilir, örneğin atomik <T *>: atomik <unique_ptr <T>> 'a izin verilmez ve atomik <shared_ptr <T>> bazı durumlarda kabul edilemeyecek bir ek yüke sahiptir.
atb

2
RAII kullanarak kaynak yönetimine sahip bir sınıf bildirmek için yeni çağırmanız ve doğru silmeniz mi gerekiyor?
VinGarcia

2
@VinGarcia Buradaki nokta, çoğu kullanıcı / istemci (yani kütüphane olmayan) kodun asla yazmak zorunda olmaması newya da delete. Standart bileşenler işi yapamaz kaynakları yönetmek için tasarlanmış Sınıflar, ders yapmaları gereken ne yapabiliriz, ama mesele olduğunu onlar yönettikleri bellekte değil, son kullanıcı kodu ile çirkin şeyler. Yani, kendi kütüphane / yardımcı sınıfı yapmak yapmak new/ deleteve bunlardan yerine o sınıfını kullanın.
underscore_d

Yanıtlar:


265

deleteyine de çek yapar, bu yüzden yanınızda kontrol etmek ek yük ekler ve daha çirkin görünür. Bir çok iyi bir uygulama NULL'A sonra işaretçi ayarlıyor delete(çift silme ve diğer benzer bellek bozulması problemleri kaçınarak yardımcı olur).

Ben de deletevarsayılan olarak parametre gibi NULL ayarlıyor olsaydı isterim

#define my_delete(x) {delete x; x = NULL;}

(R ve L değerlerini biliyorum, ama hoş olmaz mıydı?)


72
Silme sırasında birini NULL olarak ayarlasanız bile, aynı nesneyi gösteren başka birkaç işaretçi olabileceğini unutmayın.
sth

13
Kodumdaki çoğu durumda, işaretçi silindikten sonra kapsam dışına çıkar. Yalnızca NULL olarak ayarlamaktan çok daha güvenli.
jalf

142
Bir çok tanrı uygulama olduğu değil silme NULL'A sonra işaretçi ayarı. İşaretçiyi sildikten sonra NULL olarak ayarlamak, bellek ayırma hatalarını maskeliyor, ki bu çok kötü bir şey. İki kez bir işaretçi silmez doğru bir program ve iki kez bir işaretçi silinir mi bir program olmalıdır çökmesine.
Damon

15
@Alice: Standardın bu konuda söyledikleri önemsiz. Standart, bir boş göstergenin silinmesinin 30 yıl önce saçma bir nedenden dolayı geçerli olduğunu belirlediğinden, yasaldır (büyük olasılıkla C mirası). Ancak aynı işaretçiyi iki kez silmek (bit desenini değiştirdikten sonra bile) hala ciddi bir program hatasıdır. Standardın ifadesi ile değil, program mantığı ve sahipliği ile. Boş gösterici silinirken, boş gösterici hiçbir nesneye karşılık gelmediğinden , hiçbir şey silinemez. Bir program, bir nesnenin geçerli olup olmadığını ve ona kimin sahip olduğunu ve ne zaman silinebileceğini tam olarak bilmelidir.
Damon

27
@Damon Bununla birlikte, acımasız mülkiyet kurallarınızın bu iptallerine rağmen, kilitsiz yapılar kilit tabanlı olanlardan daha sağlamdır. Ve evet, iş arkadaşlarım gerçekten bu yapıların sağladığı gelişmiş yürütme profili ve korudukları sıkı iplik güvenliği için beni seviyorlar, bu da kod hakkında akıl yürütmeyi kolaylaştırıyor (bakım için harika). Ancak, bunların hiçbirinin veya zımni kişisel saldırınızın herhangi bir doğruluk, geçerlilik veya mülkiyet tanımı ile ilgisi yoktur. Önerdiğiniz şey iyi bir temel kuraldır, ancak evrensel bir yasa değildir ve standartta yer almaz.
Alice

77

C ++ 0x taslak Standardından.

$ 5.3.5 / 2 - "[...] Her iki alternatifte de silme işleneni değeri boş bir işaretçi değeri olabilir. [... '"

Tabii ki, hiç kimse NULL değerine sahip bir işaretçiyi 'silmez', ancak bunu yapmak güvenlidir. İdeal olarak bir boş gösterici silme yapan bir kod olmamalıdır. Ancak, bir döngüde işaretçilerin silinmesi (örneğin bir kapta) bazen yararlı olur. NULL işaretçi değerinin silinmesi güvenli olduğundan, silme mantığını NULL işleneninin silinmesi için açık kontroller olmadan gerçekten yazılabilir.

Bir kenara, C Standard $ 7.20.3.2 ayrıca bir NULL işaretçisinde 'free' eyleminin olmadığını söylüyor.

Serbest fonksiyon, ptr ile gösterilen alanın serbest bırakılmasına, yani daha fazla tahsis için müsait olmasına neden olur. Ptr bir boş gösterici ise, hiçbir eylem gerçekleşmez.


2
Optimize edilmemiş kodda kasıtlı olarak verimsizlik getirmediyse, alıntıları için bu cevabı gerçekten istiyorum. Kabul edilen yanıtın belirttiği gibi, boş bir işaretçinin silinmesi işlem yapılmaz. Bu nedenle, bir işaretçiyi silmeden önce boş olup olmadığını kontrol etmek tamamen yabancıdır.
codetaku

47

Evet güvenlidir.

Boş göstericiyi silmenin hiçbir zararı yoktur; ayrılmamış işaretçiler sıfıra başlatılır ve daha sonra silinirse, genellikle bir işlevin kuyruğundaki test sayısını azaltır.


Önceki cümle karışıklığa yol açtığından, tarif edilenlerin istisnası güvenli olmayan bir örneği:

void somefunc(void)
{
    SomeType *pst = 0;
    AnotherType *pat = 0;

    
    pst = new SomeType;
    
    if (…)
    {
        pat = new AnotherType[10];
        
    }
    if (…)
    {
        code using pat sometimes
    }

    delete[] pat;
    delete pst;
}

Örnek kodla seçilebilecek her türlü nit vardır, ancak konsept (umarım) açıktır. İşaretçi değişkenleri sıfıra sıfırlanır, böylece deleteişlevin sonundaki işlemlerin kaynak kodunda boş olup olmadıklarını sınamaları gerekmez; kütüphane kodu bu kontrolü yine de gerçekleştirir.


Bunu anlamak için bunu birkaç kez okumak zorunda kaldım. Onları yöntemin en üstünde sıfırlamak veya kuyruk sırasında değil, kesinlikle sıfırlamak mı demek istiyorsunuz? Aksi takdirde, hem sıfırlamayı hem de silmeyi kaldırabilirsiniz.
Lorne Marquis

1
@EJP: Bir fonksiyonun bir tamamen mantıksız değil anahat olabilir: void func(void) { X *x1 = 0; Y *y1 = 0; … x1 = new[10] X; … y1 = new[10] Y; … delete[] y1; delete[] x1; }. Herhangi bir blok yapı veya atlama göstermedim, ancak delete[]başlangıçtaki başlatmalar nedeniyle sondaki işlemler güvenlidir. Eğer bir şey x1tahsis edildikten sonra sona erdi ve daha önce y1tahsis edildiğinde ve başlatılmamışsa, y1tanımsız davranış olurdu - ve kod silme işlemlerinden önce boşluğu (ve x1ve y1) için test edebilirken , yapmaya gerek yoktur. yani.
Jonathan Leffler

22

Boş bir işaretçiyi silmenin bir etkisi yoktur. Mutlaka iyi bir kodlama stili değildir çünkü gerekli değildir, ama kötü de değildir.

İyi kodlama uygulamaları arıyorsanız, bunun yerine akıllı işaretçiler kullanmayı düşünün delete.


20
insanların bir NULL işaretçisi silmek istedikleri zaman NULL içerip içermediğinden emin olmadıkları zamandır.
Tony Delroy

@Tony: Demek istediğim, sadece bir etkisi olmayacaktı ve bazen NULL içeren bir işaretçiyi silen böyle bir kodun varlığı mutlaka kötü değil.
Brian R. Bondy

3
IMO yedek kontrolleri performans, okunabilirlik ve bakım kolaylığı açısından kesinlikle kötüdür.
paulm

@paulm OP kesinlikle bu tür kötülerden değil, Seg Fault / UB türünden daha kötü.
Kış


3

Silme işlecini aşırı yüklemediğiniz sürece güvenlidir. delete operatörünü aşırı yüklediyseniz ve null koşulunu işlemiyorsanız, o zaman hiç güvenli değildir.


Cevabınız için herhangi bir açıklama ekleyebilir misiniz?
Marcin Nabiałek

-2

Böyle olduğuna yaşamış değil güvenli (VS2010) [] NULL (yani dizi sözdizimi) silin. Bunun C ++ standardına göre olup olmadığından emin değilim.

Bu ise silme NULL (skaler sözdizimi) güvenli.


6
Bu yasa dışı ve buna inanmıyorum.
Konrad Rudolph

5
Boş gösterici silebilirsiniz. Eğer sizin için kırılıyorsa, muhtemelen kodda bir hata var demektir.
Gizemli

3
§5.3.2 İkinci alternatifte (diziyi sil), silme işleneni değeri bir boş işaretçi değeri veya bir önceki dizi yeni ifadesinden kaynaklanan bir işaretçi değeri olabilir.
sp2danny

1
@Opux Cevapta iddia edilen VS2010 davranışı. Diğer yorumlarda açıklandığı gibi, güvenli delete[] NULL.
Konrad Rudolph

1
@Opux Bu yüzden “yanlış” değil, “İnanmıyorum” yazdım. Ama hala yapmıyorum ve bu standardın oldukça çirkin, aptal bir ihlali olurdu. VC ++ aslında standardın kısıtlamalarına uymada oldukça iyidir ve onları ihlal ettiği yerler tarihsel olarak mantıklıdır.
Konrad Rudolph
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.