Silme [], işlenen dizisinin boyutunu nasıl “bilir”?


250
Foo* set = new Foo[100];
// ...
delete [] set;

Dizinin sınırlarını geçemezsiniz delete[]. Peki bu bilgiler nerede saklanıyor? Standart mı?


sourceforge.net/projects/fastmm açık kaynaklıdır ve bellek yöneticisinin yerini alır. Burada bellek yönetiminin nasıl çalıştığını ve anıları ayırmak ve silmek için bilgilerin nereden geldiğini öğrenebilirsiniz.

1
FastMM'nin yalnızca Delphi / C ++ Builder derleyicilerine özgü olduğunu, C ++ için genel amaçlı bir bellek yöneticisi olmadığını unutmayın. C ++ ile bile yazılmamıştır.
Remy Lebeau

Yanıtlar:


181

Öbek üzerinde bellek ayırdığınızda, ayırıcısı ne kadar bellek ayırdığınızı takip edecektir. Bu genellikle tahsis ettiğiniz hafızadan hemen önce bir "baş" segmentinde saklanır. Bu şekilde, hafızayı boşaltmanın zamanı geldiğinde, ayrıştırıcı ne kadar hafızanın boşaltılacağını tam olarak bilir.


4
Bunun yalnızca C ++ 'daki dizi ayırmaları için geçerli olduğunu unutmayın. Diğer tüm ayırmalar türün boyutuna bağlıdır. Bazı kütüphaneler, tüm ayırma boyutlarını, genellikle yalnızca hata ayıklama modunda depolar.
Zan Lynx

97
Bu bilgilerin programcıya ulaşmaması için kesinlikle hiçbir neden yoktur. Bir işleve bir işaretçi geçirip serbest bırakabilirim, ancak aynı işlevin boyutunu kendim elde etmek için fazladan bir parametre geçmem gerekiyor. Bu bir anlam ifade ediyor mu?
Mark Ruzon

26
@Mark, küçük bir anlam ifade eder, çünkü teoride, ayırıcıyı her zaman tahsis edilen bloğun boyutunu saklamak için serbest bırakır (bu, istenen bloğun boyutundan farklı olabilir ). Bazı ayırıcı tasarımları bu bilgilere kendi amaçları için ihtiyaç duyabilir veya dizi bilgisi olmayan yığın ayırmalarının boyutunu izlemek için tür bilgisini kullanacak kadar karmaşık olmayabilir. dizi boyutunu kendiniz geçmeniz gerekir) küçük bir takılma olabilir, ancak akla gelebilecek ayırıcı tasarımları üzerinde performans etkileri olabilir.
Doug McClean

33
Üzgünüm, ama bu cevap noktayı kaçırıyor. QuantumPete'in tanımladığı şey temelde "Ne freekadar bellek ayırılacağını nasıl bilir". Evet, bellek bloğu boyutu " mallocnormalde bloğun kendisinde " tarafından bir yerde saklanır , bu yüzden böyle freebilir. Ancak, new[]/ delete[]farklı bir hikaye. İkincisi temelde malloc/ üstünde çalışır free. new[]ayrıca oluşturduğu öğe sayısını bellek bloğunda (bağımsız olarak malloc) saklar , böylece daha sonra delete[]bu numarayı alıp uygun sayıda yıkıcıyı çağırmak için kullanabilir.
AnT

26
Yani fiziksel olarak blokta iki sayaç saklanır: blok boyutu (by malloc) ve eleman sayısı (by new[]). Birincisinin ikincisini hesaplamak için kullanılamayacağını unutmayın, çünkü genel olarak bellek bloğunun boyutu istenen boyut dizisi için gerçekten gerekenden daha büyük olabilir. Ayrıca dizi öğesi sayacının yalnızca önemsiz yıkıcıya sahip türler için gerekli olduğunu unutmayın. Önemsiz yıkıcıya sahip tipler için sayaç, new[]elbette tarafından alınmaz ve alınmaz delete[].
AnT

23

Derleyicilere yönelik yaklaşımlardan biri, biraz daha fazla bellek ayırmak ve bir kafa elemanında bir dizi elemanı saklamaktır.

Nasıl yapılacağına örnek:

Buraya

int* i = new int[4];

derleyici sizeof(int)*5bayt ayırır.

int *temp = malloc(sizeof(int)*5)

İlk sizeof(int)baytta "4" depolayacak

*temp = 4;

ve ayarla i

i = temp + 1;

Yani i5 değil 4 elemanlık bir diziyi gösterecektir.

Ve silme

delete[] i;

aşağıdaki şekilde işlenecektir:

int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)

9

Bilgiler standartlaştırılmamıştır. Ancak bu bilgiler üzerinde çalıştığım platformlarda ilk öğeden hemen önce bellekte saklanıyor. Bu nedenle teorik olarak ona erişebilir ve inceleyebilirsiniz, ancak buna değmez.

Ayrıca bu yüzden delete [] ile bellek ayırdığınızda delete [] kullanmalısınız, çünkü delete dizisi sürümü doğru miktarda belleği boşaltmanın ve uygun sayıda yıkıcı çağırmanın gerekli olduğunu (ve nerede) bildiğinden nesneler için.


5

Temel olarak bellekte düzenlenmiştir:

[info] [mem istediğiniz ...]

Bilgi, derleyiciniz tarafından ayrılan bellek miktarını depolamak için kullanılan yapıdır ve ne değildir.

Ancak bu uygulamaya bağlıdır.


4

Bu spesifikasyonda olmayan bir şey değil - uygulamaya bağlı.


3

C ++ standardında derleyiciye özgü olarak tanımlanmıştır. Bu da derleyici büyüsü demek. En az bir büyük platformda önemsiz hizalama kısıtlamaları ile kırılabilir.

delete[]Yalnızca döndürülen işaretçiler için tanımlanmış olan ve döndürülen işaretçi new[]olmayabilir, olası uygulamaları düşünebilirsiniz operator new[]. Vahşi bir uygulama tarafından döndürülen ilk int dizi sayısını saklamaktır operator new[]ve sahip new[]olduğu geçmiş ofset bir işaretçi döndürür. (Bu yüzden önemsiz olmayan hizalamalar kırılabilir new[].)

Unutmayın operator new[]/operator delete[]! = new[]/delete[].

Ayrıca, bu, C'nin ayrılan belleğin boyutunu nasıl bildiği ile dikeydir malloc.


2

Çünkü 'silinecek' dizi, 'yeni' operatörün tek bir kullanımı ile oluşturulmalıdır. 'Yeni' işlemin bu bilgiyi yığına koyması gerekirdi. Aksi takdirde, yeni ek kullanımların yığının nerede bittiğini nasıl bilebilir?


0

Standart değildir. Microsoft çalışma zamanında yeni işleç malloc () kullanır ve delete operatörü free () kullanır. Bu durumda, sorunuz aşağıdakine eşdeğerdir: free () bloğun boyutunu nasıl bilir?

Sahne arkasında, yani C çalışma zamanında, bazı defter tutma vardır.


5
Doğru değil. Ücretsiz aramadan önce, delete [] öğesinin önce yıkıcıları çağırması gerekir. Bunun için toplam tahsisat büyüklüğü yeterli değildir. Aslında yeni [] ve delete [], VC ++ 'da sade ve tahrip olmuş türler için farklı çalışır.
Suma

0

Bu, ilk başta düşündüğünüzden daha ilginç bir sorundur. Bu cevap olası bir uygulama ile ilgilidir.

İlk olarak, bir düzeyde sisteminizin bellek bloğunu nasıl 'boşaltacağını' bilmek zorunda kalırken, temel malloc / free (hangi yeni / delete / new [] / delete [] genellikle çağırır) her zaman tam olarak ne kadar bellek hatırlayacağını hatırlamaz isteyebilirsiniz, yuvarlanabilir (örneğin, 4K'nın üzerinde olduğunuzda, genellikle bir sonraki 4K boyutlu bloğa yuvarlanır).

Bu nedenle, bellek bloğunun boyutunu alabilseniz bile, bu yeni [] ed bellekte daha küçük olabileceği için kaç değer olduğunu bize söylemez. Bu nedenle, bize kaç değer olduğunu söyleyen ekstra bir tamsayı depolamamız gerekir.

DIŞINDA, inşa edilen tipin bir yıkıcı yoksa, o zaman silme [], bellek bloğunu boşaltmak dışında bir şey yapmak zorunda değildir ve bu nedenle hiçbir şey depolamak zorunda değildir!

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.