İkisi arasında önemli bir fark vardır.
Her şey ile ayrılan değil new
çok C # değer türleri gibi davranır (ve insanlar genellikle bu cisimler muhtemelen en yaygın / bariz bir durumdur yığını, tahsis değil, her zaman doğru olduğunu söylüyorlar. Daha doğrusu, tahsis nesneleri kullanmadan new
sahip otomatik depolama duration
Ayrılan her şey new
öbek üzerinde ayrılır ve C # işaretindeki referans türleri gibi ona bir işaretçi döndürülür.
Yığına ayrılan her şeyin derleme zamanında belirlenmiş sabit bir boyutu olmalıdır (derleyici yığın işaretçisini doğru ayarlamalıdır veya nesne başka bir sınıfın üyesiyse, diğer sınıfın boyutunu ayarlamalıdır) . Bu yüzden C # 'daki diziler referans tipleridir. Olmalıdırlar, çünkü referans türleriyle çalışma zamanında ne kadar bellek isteyeceğine karar verebiliriz. Aynı şey burada da geçerlidir. Yalnızca sabit boyutlu diziler (derleme zamanında belirlenebilen bir boyut) otomatik depolama süresi (yığın üzerinde) ile ayrılabilir. Dinamik boyutta diziler, çağrılarak yığın üzerine tahsis edilmelidir new
.
(Ve işte C # ile benzerlik durur)
Şimdi, yığına ayrılan her şeyin "otomatik" depolama süresi vardır (bir değişkeni aslında olarak bildirebilirsiniz auto
, ancak başka bir depolama türü belirtilmediğinde varsayılan değerdir, bu nedenle anahtar kelime pratikte gerçekten kullanılmaz, ancak burada gelen)
Otomatik saklama süresi tam olarak nasıl göründüğü anlamına gelir, değişkenin süresi otomatik olarak ele alınır. Buna karşılık, öbekte tahsis edilen herhangi bir şey sizin tarafınızdan manuel olarak silinmelidir. İşte bir örnek:
void foo() {
bar b;
bar* b2 = new bar();
}
Bu işlev dikkate değer üç değer oluşturur:
Hat 1 üzerinde, bir değişken bildirir b
Çeşidi bar
yığın (otomatik süresi) hakkında.
2. satırda , yığın üzerinde bir bar
işaretçi b2
(otomatik süre) bildirir ve yeni bir çağrı bar
yapar ve öbek üzerinde bir nesne tahsis eder. (dinamik süre)
İşlev döndüğünde, aşağıdakiler gerçekleşir: Birincisi, b2
kapsam dışına çıkar (imha sırası her zaman inşaat sırasının tersidir). Ama b2
sadece bir işaretçi, bu yüzden hiçbir şey olmuyor, kapladığı bellek basitçe serbest bırakılıyor. Ve daha önemlisi, hafıza işaret ( bar
öbek üzerinde örneğin) dokundu DEĞİLDİR. Yalnızca imleç serbest bırakılır, çünkü yalnızca imlecin otomatik süresi vardır. İkincisi, b
kapsam dışına çıkar, bu nedenle otomatik süresine sahip olduğundan, yıkıcısı çağrılır ve bellek boşaltılır.
Ve bar
öbekteki örnek? Muhtemelen hala oradadır. Kimse onu silmek için uğraşmadı, bu yüzden hafızayı sızdırdık.
Bu örnekten, otomatik süreye sahip herhangi bir şeyin , yıkıcısının kapsam dışına çıktığında çağrılmasını garanti ettiğini görebiliriz . Bu yararlı. Ancak öbekte tahsis edilen her şey, ihtiyacımız olduğu sürece sürer ve dizilerdeki gibi dinamik olarak boyutlandırılabilir. Bu da faydalı. Bunu bellek ayırmalarımızı yönetmek için kullanabiliriz. Ya Foo sınıfı, yapıcısında öbek üzerinde bir miktar bellek ayırdıysa ve bu belleği yıkıcısında sildiyse ne olurdu. Daha sonra, her iki dünyanın en iyisini, tekrar serbest bırakılması garanti edilen güvenli bellek ayırmalarını elde edebiliriz, ancak her şeyi yığının üzerinde olmaya zorlama sınırlamaları olmadan.
Ve çoğu C ++ kodu tam olarak nasıl çalışır. std::vector
Örneğin standart kütüphaneye bakın . Bu genellikle yığına tahsis edilir, ancak dinamik olarak boyutlandırılabilir ve yeniden boyutlandırılabilir. Ve bunu hafızanın içerisine belleği gerektiği gibi ayırarak yapar. Sınıfın kullanıcısı bunu asla görmez, bu nedenle bellek sızıntısı veya ayırdığınız şeyi temizlemeyi unutma şansı yoktur.
Bu ilke RAII (Kaynak Edinimi Başlatma'dır) olarak adlandırılır ve edinilmesi ve serbest bırakılması gereken herhangi bir kaynağa genişletilebilir. (ağ soketleri, dosyalar, veritabanı bağlantıları, senkronizasyon kilitleri). Hepsi kurucuda edinilebilir ve yıkıcıda serbest bırakılabilir, böylece elde ettiğiniz tüm kaynakların tekrar serbest bırakılacağı garanti edilir.
Genel bir kural olarak, asla yeni / delete komutunu doğrudan doğrudan üst düzey kodunuzdan kullanmayın. Her zaman hafızayı sizin için yönetebilecek ve tekrar boşaltılmasını sağlayacak bir sınıfa sarın. (Evet, bu kuralın istisnaları olabilir. Özellikle, akıllı işaretçiler new
doğrudan aramanızı ve işaretçiyi yapıcısına geçirmenizi gerektirir , bu da daha sonra devralıp delete
doğru bir şekilde çağrılmasını sağlar. Ancak bu hala çok önemli bir başparmak kuralıdır. )