Foo* set = new Foo[100];
// ...
delete [] set;
Anda tidak meneruskan batasan array ke delete[]
. Tetapi di mana informasi itu disimpan? Apakah standar?
Foo* set = new Foo[100];
// ...
delete [] set;
Anda tidak meneruskan batasan array ke delete[]
. Tetapi di mana informasi itu disimpan? Apakah standar?
Jawaban:
Ketika Anda mengalokasikan memori pada heap, pengalokasi Anda akan melacak berapa banyak memori yang telah Anda alokasikan. Ini biasanya disimpan dalam segmen "head" tepat sebelum memori yang Anda peroleh dialokasikan. Dengan begitu ketika saatnya membebaskan memori, de-alokasi tahu persis berapa banyak memori yang harus dibebaskan.
free
mengetahui berapa banyak memori yang harus dialokasikan". Ya, ukuran blok memori disimpan "di suatu tempat" oleh malloc
(biasanya di blok itu sendiri), jadi begitulah caranya free
. Namun, new[]
/ delete[]
adalah cerita yang berbeda. Yang terakhir pada dasarnya bekerja di atas malloc
/ free
. new[]
juga menyimpan sejumlah elemen yang dibuatnya dalam blok memori (terlepas dari malloc
), sehingga nantinya delete[]
dapat mengambil dan menggunakan nomor itu untuk memanggil jumlah destruktor yang tepat.
malloc
) dan jumlah elemen (berdasarkan new[]
). Perhatikan, bahwa yang pertama tidak dapat digunakan untuk menghitung yang terakhir, karena secara umum ukuran blok memori bisa lebih besar dari yang sebenarnya diperlukan untuk array ukuran yang diminta. Perhatikan juga bahwa penghitung elemen array hanya diperlukan untuk tipe dengan destruktor non-sepele. Untuk jenis dengan destruktor sepele penghitung tidak disimpan oleh new[]
dan, tentu saja, tidak diambil oleh delete[]
.
SALAH SATU pendekatan untuk kompiler adalah mengalokasikan sedikit lebih banyak memori dan untuk menyimpan sejumlah elemen dalam elemen head.
Contoh bagaimana itu bisa dilakukan:
Sini
int* i = new int[4];
kompiler akan mengalokasikan sizeof(int)*5
byte.
int *temp = malloc(sizeof(int)*5)
Akan menyimpan "4" dalam sizeof(int)
byte pertama
*temp = 4;
dan mengatur i
i = temp + 1;
Jadi i
akan menunjuk ke array 4 elemen, bukan 5.
Dan penghapusan
delete[] i;
akan diproses dengan cara berikut:
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)
Informasi tidak terstandarisasi. Namun dalam platform yang saya kerjakan pada informasi ini disimpan dalam memori tepat sebelum elemen pertama. Karena itu Anda secara teoritis dapat mengaksesnya dan memeriksanya, namun itu tidak sepadan.
Ini juga mengapa Anda harus menggunakan delete [] ketika Anda mengalokasikan memori dengan baru [], karena versi array dari delete tahu bahwa (dan di mana) ia perlu mencari untuk membebaskan jumlah memori yang tepat - dan memanggil jumlah destruktor yang sesuai. untuk benda-benda.
Pada dasarnya ini diatur dalam memori sebagai:
[info] [Anda minta ...]
Di mana info adalah struktur yang digunakan oleh kompiler Anda untuk menyimpan jumlah memori yang dialokasikan, dan apa yang tidak.
Ini tergantung implementasi meskipun.
Ini didefinisikan dalam standar C ++ untuk menjadi kompiler spesifik. Yang berarti sihir kompiler. Ini dapat memutuskan dengan pembatasan penyelarasan non-sepele pada setidaknya satu platform utama.
Anda bisa memikirkan kemungkinan implementasi dengan menyadari bahwa delete[]
hanya ditentukan untuk pointer yang dikembalikan oleh new[]
, yang mungkin bukan pointer yang sama seperti yang dikembalikan oleh operator new[]
. Salah satu implementasi di wild adalah untuk menyimpan jumlah array di int pertama yang dikembalikan oleh operator new[]
, dan telah new[]
mengembalikan pointer offset di masa lalu. (Inilah sebabnya mengapa keberpihakan non-sepele bisa pecah new[]
.)
Ingatlah itu operator new[]/operator delete[]
! = new[]/delete[]
.
Plus, ini ortogonal untuk bagaimana C mengetahui ukuran memori yang dialokasikan oleh malloc
.
Karena array yang akan 'dihapus' seharusnya dibuat dengan menggunakan satu operator 'baru'. Operasi 'baru' seharusnya meletakkan informasi itu di tumpukan. Kalau tidak, bagaimana cara tambahan menggunakan baru tahu di mana tumpukan berakhir?
Itu tidak standar. Dalam runtime Microsoft, operator baru menggunakan malloc () dan operator hapus menggunakan gratis (). Jadi, dalam pengaturan ini pertanyaan Anda setara dengan yang berikut: Bagaimana cara bebas () mengetahui ukuran blok?
Ada beberapa pembukuan yang terjadi di belakang layar, yaitu di runtime C.
Ini adalah masalah yang lebih menarik daripada yang mungkin Anda pikirkan pada awalnya. Balasan ini adalah tentang satu kemungkinan implementasi.
Pertama, ketika pada tingkat tertentu sistem Anda harus tahu bagaimana 'membebaskan' blok memori, malloc yang mendasari / gratis (yang biasanya dipanggil / hapus / baru [] / hapus [] umumnya) tidak selalu ingat persis berapa banyak memori Anda meminta, itu bisa dibulatkan ke atas (misalnya, setelah Anda berada di atas 4K sering dibulatkan ke blok berukuran 4K berikutnya).
Oleh karena itu, bahkan jika bisa mendapatkan ukuran blok memori, itu tidak memberi tahu kami berapa banyak nilai dalam memori ed [] baru, karena bisa lebih kecil. Oleh karena itu, kita harus menyimpan integer tambahan yang memberitahu kita berapa banyak nilai yang ada.
KECUALI, jika tipe yang sedang dibangun tidak memiliki destruktor, maka hapus [] tidak harus melakukan apa pun kecuali membebaskan blok memori, dan karenanya tidak perlu menyimpan apa pun!