Властивості вказівника на масив нульової довжини


21

Розглянемо

int main()
{
    auto a = new int[0];
    delete[] a; // So there's no memory leak
}

Між ініціалізацією копіювання та видаленням, чи можете ви читати вказівник на a + 1?

Крім того, це мова дозволяє компілятор для набору aв nullptr?


2
@Fareanor: Ви можете читати aточно (ви, звичайно, не можете її знехтувати).
Вірсавія

8
@RasmiRanjanNayak: Це багряник.
Вірсавія

2
@RasmiRanjanNayak О мій ... ні
Тед Лінгмо

1
@TedLyngmo: Коли я кажу "прочитати вказівник на a + 1", чи не визначений наступний код auto b = a + 1;поведінки? (Я думаю це).
Вірсавія

2
@Ayxan Я б здогадався у тому випадку, коли 0насправді є результатом якогось виразу, про який ви не знатимете до часу виконання. Оскільки new int[0]це безпечно, це може врятувати вас турбуючись про деякі розгалуження / особливі випадки. Уявіть, якби я ініціалізував std::vectorс std::vector<int> v(0);.
scohe001

Відповіді:


3
    auto a = new int[0];

Відповідно до [basic.compound.3] , значення, яке зберігається в, aповинно бути одним із таких:

  1. Вказівник на об’єкт (типу int)
  2. Вказівник повз кінець об’єкта
  3. Нуль
  4. Недійсний

Ми можемо виключити першу можливість, оскільки не було intпобудовано об'єктів типу . Третя можливість виключається, оскільки C ++ вимагає повернення ненульового вказівника (див. [Basic.stc.dynamic.allocation.2] ). Таким чином, у нас залишаються дві можливості: вказівник повз кінець об'єкта або недійсний покажчик.

Я був би схильний розглядати aяк вказівник минулого кінця, але не маю поважних посилань, щоб остаточно це встановити. (Однак, в [basic.stc] це є сильним наслідком , бачачи, як можна зробити deleteцей вказівник.) Тож я розберуся у цій відповіді обома можливостями.

Між ініціалізацією копіювання та видаленням, чи можете ви читати вказівник на a + 1?

Поведінка не визначена, як це продиктовано [expr.add.4] , незалежно від того, яка можливість зверху застосовується.

Якщо aвказівник минулого кінця, то вважається, що він вказує на гіпотетичний елемент при індексі 0масиву без елементів. Додавання цілого числа jдо aвизначається лише тоді 0≤0+j≤n, коли nрозмір масиву. У нашому випадку nдорівнює нулю, тому сума a+jвизначається лише тоді, коли jє 0. Зокрема, додавання 1не визначено.

Якщо aвін недійсний, ми чітко потрапляємо в "В іншому випадку поведінка не визначена". (Не дивно, що визначені випадки охоплюють лише дійсні значення вказівника.)

Крім того, це мова дозволяє компілятор для набору aв nullptr?

Ні. Із вищезгаданого [basic.stc.dynamic.allocation.2] : "Якщо запит успішний, значення, яке повертається функцією змінного розподілу, є ненульовим значенням вказівника" . Також є виноска, що зазначає, що C ++ (але не C) вимагає ненульового вказівника у відповідь на нульовий запит.


1
Якщо це недійсне значення вказівника, у вас виникнуть серйозні проблеми з eel.is/c++draft/basic.stc#4
TC

@TC Щоправда, це прямо означає, що воно не може бути невірним значенням вказівника.
JaMiT

23

За останній час РГСА рефлектора обговорення в результаті редакційного випуску 3178 , new int[0]продукує те , що в даний час називається «прийшов до кінця» значення покажчика .

Звідси випливає, що aне може бути нульовим, і a + 1не визначено [expr.add] / 4 .


4
"Під час нещодавнього обговорення рефлектора CWG в результаті редакційного випуску 3178 new int[0]створюється те, що в даний час називається" значенням вказівника минулого кінця ". Це не точно. Не було багато дискусій. Одна людина припустила, що значення повинно бути "вказівник на кінець об'єкта", і це твердження було поставлено під сумнів, оскільки у випадку масиву з 0елементами немає жодного об'єкта, який повинен бути минулим.
юрист з мови

@LanguageLawyer, мабуть, немає сумнівів, що a + 1це не визначено в будь-якому випадку, тому ваша думка стосується лише того, чи aможе бути нульовим?
ММ

Не було суперечок щодо передбачуваної семантики, а також те, що поточна назва для цієї категорії значень вказівників погано підходить для цього сценарію.
ТК

@MM Я думаю, що a + 1це не визначено, і, можливо, отримане значення вказівника буде називатися "покажчик минулого кінця". Я не кажу, що відповідь неправильна. Це трохи не точно, тому що можна зрозуміти, що тривала дискусія з консенсусом, що для вирішення проблеми достатньо лише конкретизації того, що результат є "покажчиком на кінець". Проблема з "покажчиком минулого кінця" полягає в тому, що це минулий кінець якогось об'єкта, і віднімання 1такого значення вказівника дає один вказівник на об'єкт, що, мабуть, не повинно бути випадком для масивів 0елементів.
юрист з мови

2
@Bathsheba Як ви думаєте, може бути щось більш авторитетне щодо дефектних формулювань?
юрист з мови
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.