Простий тестовий додаток:
cout << new int[0] << endl;
Виходи:
0x876c0b8
Так виглядає, що це працює. Що говорить про це стандарт? Чи завжди законно "виділяти" порожній блок пам'яті?
Простий тестовий додаток:
cout << new int[0] << endl;
Виходи:
0x876c0b8
Так виглядає, що це працює. Що говорить про це стандарт? Чи завжди законно "виділяти" порожній блок пам'яті?
Відповіді:
З 5.3.4 / 7
Коли значення виразу у прямому новому деклараторі дорівнює нулю, функція розподілу викликається для виділення масиву без елементів.
З 3.7.3.1/2
Ефект перенаправлення покажчика, повернутого як запит на нульовий розмір, не визначений.
Також
Навіть якщо розмір запитуваного простору [по новому] дорівнює нулю, запит може не виконати.
Це означає, що ви можете це зробити, але ви не можете на законних підставах (у чітко визначеному порядку на всіх платформах) знецінювати отриману пам’ять - ви можете передати її лише для видалення масиву - і ви повинні її видалити.
Ось цікава примітка (тобто не нормативна частина стандарту, але включена в цілі опису), що додається до речення від 3.7.3.1/2
[32. Намір полягає в тому, щоб оператор new () був реалізований за допомогою виклику malloc () або calloc (), тому правила практично однакові. C ++ відрізняється від C тим, що вимагає нульового запиту повернути ненульовий покажчик.]
new[]
a delete[]
- незалежно від розміру. Зокрема, під час дзвінка new[i]
вам потрібно трохи більше пам’яті, ніж той, який ви намагаєтеся виділити, щоб зберігати розмір масиву (який згодом використовується під delete[]
час
Так, законно виділити такий масив нульового розміру, як цей. Але ви також повинні її видалити.
int ar[0];
це незаконно, чому це все в порядку?
sizeof (type)
, очікується, що він ніколи не поверне нуль. Дивіться, наприклад: stackoverflow.com/questions/2632021/can-sizeof-return-0-zero
Що говорить про це стандарт? Чи завжди законно "виділяти" порожній блок пам'яті?
Кожен об'єкт має унікальну ідентичність, тобто унікальну адресу, що передбачає ненульову довжину (фактичний об'єм пам'яті буде мовчки збільшено, якщо ви попросите нульових байт).
Якщо ви виділили більше одного з цих об'єктів, ви побачите, що вони мають різні адреси.
operator []
також десь зберігає розмір масиву (див. isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array ). Отже, якщо реалізація виділяє кількість байтів з даними, вона може просто виділити для кількості байтів і 0 байт для даних, повертаючи вказівник 1-останнього-останнього.
operator new[]
повинні повертати різні покажчики. До речі, new expression
має деякі додаткові правила (5.3.4). Я не міг знайти жодної підказки, що new
з розміром 0 насправді потрібно виділити що-небудь. Вибачте, я подав заяву, оскільки я вважаю, що ваша відповідь не відповідає на питання, а надає певні суперечливі твердження.
new[]
реалізація може повертати адреси в діапазоні, де не відображається динамічна пам'ять, отже, насправді не використовується жодна пам'ять (при використанні адресного простору)
while(!exitRequested) { char *p = new char[0]; delete [] p; }
цикл без переробки покажчиків, розвалиться в пил, перш ніж у нього може не вистачити адресного простору, але на платформі з 32-бітовими вказівниками, який би був набагато менш розумне припущення.
Так, виділяти 0
розмірний блок за допомогою цілком законно new
. Ви просто не можете з цим зробити нічого корисного, оскільки для вас немає дійсних даних. int[0] = 5;
є незаконним.
Однак я вважаю, що стандарт дозволяє такі речі, як malloc(0)
повернення NULL
.
Вам все одно знадобиться delete []
будь-який вказівник, який ви отримаєте від розподілу.
Цікаво, що C ++ вимагає, щоб новий оператор повернув законний покажчик, навіть коли запитується нульовий байт. (Вимога цього дивного звучання спрощує речі в інших місцях мови.)
Я виявив, що " Ефективне C ++" третього видання сказано так у "Пункт 51: Дотримуйтесь конвенції під час написання нового та видалення".
Я гарантую вам, що новий int [0] коштує вам додаткового місця, оскільки я його протестував.
Наприклад, використання пам'яті
int **arr = new int*[1000000000];
значно менше, ніж
int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
arr[i]=new int[0];
}
Використання пам’яті другого фрагмента коду мінус значення першого фрагмента коду - це пам'ять, яка використовується для численного нового int [0].