Foo* set = new Foo[100];
// ...
delete [] set;
Ви не переходите межі масиву до delete[]
. Але де зберігається ця інформація? Це стандартизовано?
Foo* set = new Foo[100];
// ...
delete [] set;
Ви не переходите межі масиву до delete[]
. Але де зберігається ця інформація? Це стандартизовано?
Відповіді:
Виділяючи пам'ять на купі, ваш розподільник буде відслідковувати кількість пам'яті, яку ви виділили. Зазвичай він зберігається в сегменті "голова" безпосередньо перед пам'яттю, яку ви виділили. Таким чином, коли прийшов час звільнити пам'ять, делокатор точно знає, скільки пам'яті звільнити.
free
знати, скільки пам'яті потрібно розібрати". Так, розмір блоку пам'яті зберігається "десь" malloc
(як правило, у самому блоці), тож, як free
відомо. Однак new[]
/ delete[]
це інша історія. Останні в основному працюють поверх malloc
/ free
. new[]
також зберігає кількість створених ним елементів у блоці пам’яті (незалежно від malloc
), щоб потім delete[]
можна було отримати та використати це число для виклику потрібної кількості деструкторів.
malloc
) та кількість елементів (за new[]
). Зауважте, що перший не може бути використаний для обчислення останнього, оскільки загалом розмір блоку пам'яті може бути більшим, ніж дійсно необхідний для масиву запитуваного розміру. Також зауважте, що лічильник елементів масиву потрібен лише для типів з нетривіальним деструктором. Для типів з тривіальним деструктором лічильник не зберігається new[]
і, звичайно, не виводиться delete[]
.
Один із підходів для компіляторів - виділити трохи більше пам’яті та зберігати кількість елементів у головному елементі.
Приклад, як це можна зробити:
Ось
int* i = new int[4];
компілятор виділить sizeof(int)*5
байти.
int *temp = malloc(sizeof(int)*5)
Збереже "4" у перших sizeof(int)
байтах
*temp = 4;
і встановити i
i = temp + 1;
Так i
буде вказувати на масив з 4 елементів, а не 5.
І видалення
delete[] i;
буде оброблено наступним чином:
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)
Інформація не стандартизована. Однак на платформах, над якими я працював, ця інформація зберігається в пам'яті безпосередньо перед першим елементом. Тому ви могли теоретично отримати доступ до нього та оглянути його, однак це не варто.
Крім того, тому ви повинні використовувати delete [], коли ви виділяли пам'ять за допомогою нового [], оскільки версія масиву delete знає, що (і де) потрібно шукати, щоб звільнити потрібний об'єм пам'яті - і викликати відповідну кількість деструкторів для об'єктів.
В основному його розташовано в пам'яті як:
[info] [пам'ять, про яку ти просив ...]
Де інформація - це структура, використовувана вашим компілятором для зберігання кількості виділеної пам'яті, а що ні.
Від цього залежить реалізація.
Він визначений у стандарті C ++ для конкретного компілятора. Що означає магію компілятора. Він може порушуватися з нетривіальними обмеженнями вирівнювання принаймні на одній з основних платформ.
Ви можете подумати про можливі реалізації, зрозумівши, що delete[]
це визначено лише для повернених вказівниками new[]
, які можуть бути не тим самим покажчиком, як поверненим operator new[]
. Однією реалізацією в природі є збереження підрахунку масиву у першому поверненому int operator new[]
та new[]
повернення зміщення покажчика минулого. (Ось чому нетривіальні вирівнювання можуть порушитися new[]
.)
Майте на увазі, що operator new[]/operator delete[]
! = new[]/delete[]
.
Плюс, це ортогонально тому, як C знає розмір пам'яті, виділений malloc
.
Оскільки масив, який слід видалити, повинен був бути створений за допомогою одного оператора "new". "Нова" операція повинна була поставити цю інформацію в купу. В іншому випадку, як додаткові використання нових знають, де закінчується купа?
Він не стандартизований. У час виконання Microsoft новий оператор використовує malloc (), а оператор видалення використовує free (). Отже, у цьому налаштуванні ваше запитання еквівалентне наступному: Як free () знає розмір блоку?
Існує деяка бухгалтерія, яка ведеться за лаштунками, тобто під час виконання C.
Це цікавіша проблема, ніж ви могли подумати спочатку. Ця відповідь стосується однієї можливої реалізації.
По-перше, хоча на якомусь рівні ваша система повинна знати, як "звільнити" блок пам'яті, базовий malloc / free (який взагалі новий / видалити / новий [] / видалити [] зазвичай не викликає) точно не пам'ятає, скільки пам'яті ви запитаєте, він може округлюватися (наприклад, коли ви вище 4К, його часто округляють до наступного блоку розміром 4К).
Тому, навіть якщо вдасться отримати розмір блоку пам'яті, це не говорить нам, скільки значень у новій [] ed пам'яті, оскільки вони можуть бути меншими. Тому нам потрібно зберігати додаткове ціле число, вказуючи нам, скільки значень існує.
ЗА винятком, якщо тип, що будується, не має деструктора, тоді delete [] не повинен робити нічого, крім звільнення блоку пам'яті, і тому нічого не потрібно зберігати!