İşaretçiyi neden NULL olarak ayarlamıyor?


127

Silme işleminden sonra işaretçinin otomatik olarak NULL olarak ayarlanmasının neden standardın bir parçası olmadığını hep merak etmişimdir . Bu halledilirse, geçersiz bir işaretçi nedeniyle birçok çökme meydana gelmez. Ancak, standardın bunu neden kısıtlayacağına dair birkaç neden düşünebileceğimi söylemiştim:

  1. Verim:

    Ek bir talimat, deleteperformansı yavaşlatabilir .

  2. İşaretçiler yüzünden olabilir mi const?

    O zaman yine standart bu özel durum için bir şeyler yapabilirdi sanırım.

Buna izin vermemenin kesin nedenlerini bilen var mı?

Yanıtlar:


150

Stroustrup kendisi cevaplar. Bir alıntı:

C ++ bir lvalue işlenenini sıfırlamak için silme uygulamasına açıkça izin verir ve uygulamaların bunu yapacağını ummuştum, ancak bu fikir uygulayıcılar arasında popüler hale gelmemiş gibi görünüyor.

Ancak ortaya attığı ana konu, silme argümanının bir değer olması gerekmediğidir.


Sanırım bu biraz daha açıklama gerektirebilir. Ne dediğinden bile emin değilim ... Sanırım, anlayana kadar bunu araştırmaya birkaç saat ayırabileceğim daha sonra geri gelmem gerekecek. Veya daha hızlı anlamamıza yardımcı olmak için cevabı açıklayabilirsiniz.
Gabriel Staples

63

İlk olarak, null olarak ayarlamak, bellekte saklanan bir değişken gerektirir. Bir değişkende genellikle bir işaretçiniz olduğu doğrudur, ancak bazen sadece hesaplanmış bir adresteki bir nesneyi silmek isteyebilirsiniz . Silmeyi "geçersiz kılmak" imkansızdır.

Sonra performans gelir. Silme işlemi tamamlandıktan hemen sonra işaretçinin kapsam dışına çıkacağı şekilde kod yazmış olabilirsiniz . Boş ile doldurmak sadece zaman kaybıdır. Ve C ++, "gerek yok mu? O zaman bunun için para ödemek zorunda değilsiniz" ideolojisine sahip bir dildir.

Güvenliğe ihtiyacınız varsa, hizmetinizde çok çeşitli akıllı işaretçiler vardır veya kendiniz yazabilirsiniz - daha iyi ve daha akıllı.


4
İyi bir nokta hesaplanmış adres, sık
görmediğiniz bir

Bazen yeni hesaplanmış bir adresteki bir nesneyi silmek isteyebileceğinizi söylerken yeni yerleşimden mi bahsediyorsunuz? ???
Destructor

@PravasiMeet Hayır, şöyle bir şey demek istiyorumdelete (ptr + i)
sharptooth

39

O anıya işaret eden birden fazla işaretçiniz olabilir. Silme işlemi için belirttiğiniz işaretçi null olarak ayarlanmışsa, ancak diğer tüm işaretçiler ayarlanmamışsa yanlış bir güvenlik duygusu yaratır. Bir işaretçi bir adresten, bir sayıdan başka bir şey değildir. Dereference işlemine sahip bir int de olabilir. Demek istediğim, az önce sildiğiniz aynı belleğe başvuranları bulmak için her bir işaretçiyi taramanız ve onları da sıfırlamanız gerekir. Bu adres için tüm işaretçileri taramak ve onları geçersiz kılmak hesaplama açısından yoğun olacaktır, çünkü dil bunun için tasarlanmamıştır. (Bazı diller referanslarını benzer bir amacı farklı bir şekilde gerçekleştirmek için yapılandırsa da.)


19

Bir gösterici birden fazla değişkene kaydedilebilir, bunlardan birinin NULL olarak ayarlanması diğer değişkenlerde yine de geçersiz işaretçiler bırakacaktır. Yani gerçekten fazla kazanmıyorsunuz, daha çok yanlış bir güvenlik duygusu yaratıyorsunuz.

Bunun yanı sıra, istediğinizi yapan kendi işlevinizi oluşturabilirsiniz:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}

12

Çünkü gerçekten buna gerek yok ve sadece işaretçi yerine işaretçiden işaretçiye götürmeyi silmeyi gerektirdiğinden.


doğru, ancak bu aynı ek yüke neden olur
snemarch

7

deleteçoğunlukla yıkıcılarda kullanılır, bu durumda bir üyeyi NULL olarak ayarlamak anlamsızdır. Birkaç satır sonra kapanışta }üye artık yok. Atama operatörlerinde, genellikle silme işleminin ardından yine de bir atama gelir.

Ayrıca, aşağıdaki kodu yasa dışı hale getirir:

T* const foo = new T;
delete foo;

6

İşte başka bir sebep; delete öğesinin bağımsız değişkenini NULL olarak ayarladığını varsayalım:

int *foo = new int;
int *bar = foo;
delete foo;

Çubuk NULL olarak ayarlanmalı mı? Bunu genelleyebilir misin?


5

Bir işaretçiler dizisine sahipseniz ve ikinci eyleminiz boş diziyi silmekse, bellek boşaltılmak üzereyken her bir değeri null olarak ayarlamanın bir anlamı yoktur. Eğer boş olmasını istiyorsanız .. boş yazınız :)


4

C ++, örneğin kendi havuz ayırıcınızı kullanmaları için kendi operatörünüzü yeni tanımlamanıza ve silmenize olanak tanır. Bunu yaparsanız, kesinlikle adres olmayan ancak havuz dizinizdeki indeksler diyen şeylerle new ve delete kullanmak mümkündür. Bu bağlamda, NULL (0) değerinin yasal bir anlamı olabilir (havuzdaki ilk maddeye atıfta bulunarak).
Bu nedenle, NULL kümesini otomatik olarak bağımsız değişkenine silmenin anlamı her zaman - değeri geçersiz bir değere ayarla anlamına gelmez. Geçersiz değer her zaman NULL olmayabilir.


4

C ++ felsefesi "sadece kullanırsanız parasını ödeyin" dir. Sorunuza cevap verebileceğini düşünüyorum.

Ayrıca bazen silinmiş belleği kurtaracak kendi öbeğinize sahip olabilirsiniz .. veya bazen herhangi bir değişkene ait olmayan işaretçi. Veya işaretçi birkaç değişkende saklanır - bunlardan sadece birini sıfırlamak mümkündür.
Gördüğünüz gibi birçok sorunu ve olası sorunları var.


3

İşaretçiyi otomatik olarak NULL olarak ayarlamak, kötü işaretçi kullanımıyla ilgili sorunların çoğunu çözmez. Önleyeceği tek kilitlenme, onu iki kez silmeye çalışmanızdır. Ya böyle bir işaretçi üzerinde bir üye işlevi çağırırsanız? Yine de çökebilir (üye değişkenlerine eriştiği varsayılarak). C ++ sizi NULL işaretçiler üzerinde herhangi bir işlevi çağırmanızı kısıtlamaz ve bunu performans açısından da yapmamalıdır.


-1

Bu soruya garip cevaplar veren insanlar görüyorum.

ptr = NULL; Bu kadar basit bir ifade nasıl performans gecikmesine neden olabilir?

Diğer bir cevap, aynı hafıza konumuna işaret eden birden fazla işaretçiye sahip olabileceğimizi söylemektir. Elbette yapabiliriz. Bu durumda, bir işaretçi üzerindeki silme işlemi yalnızca bu işaretçiyi NULL yapar (silme, işaretçiyi NULL yapıyorsa) ve diğer işaretçi NULL olmaz ve boş olan bellek konumunu gösterir.

Bunun çözümü, kullanıcının aynı yere işaret eden tüm işaretçileri silmesi olmalıydı. Dahili olarak hafızanın zaten serbest olup olmadığını kontrol etmelidir. Yalnızca işaretçiyi BOŞ yapın.

Stroustrup silme işlemini bu şekilde çalışacak şekilde tasarlamış olabilir. Programcıların bununla ilgileneceğini düşünüyordu. Yani görmezden geldi.

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.