Свойства указателя на массив нулевой длины

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. Значение NULL
  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) требует ненулевого указателя в ответ на нулевой запрос.

JaMiT
источник
1
Если это неверное значение указателя, у вас будут серьезные проблемы с eel.is/c++draft/basic.stc#4
TC
@TC True, это действительно означает, что это не может быть недопустимым значением указателя.
JaMiT
23

Согласно недавнему обсуждению рефлектора CWG в результате редакционной проблемы 3178 , new int[0]получается то , что в настоящее время называется значением указателя «конец конца» .

Отсюда следует, что aне может быть нулевым и a + 1не определено [expr.add] / 4 .

TC
источник
4
«Согласно недавнему обсуждению рефлектора CWG в результате редакционной проблемы 3178, new int[0]получается то , что в настоящее время называется значением указателя« конец конца »». Это не точно. Там не было много дискуссий. Один человек предложил, чтобы значением было «указатель за концом объекта», и это утверждение было подвергнуто сомнению, потому что в случае массива с 0элементами не существует объекта, который должен быть после конца.
Языковой адвокат
@LanguageLawyer, кажется, нет сомнений, что a + 1в любом случае не определено, так что ваша точка зрения относится только к тому, aможет ли быть NULL?
ММ
Похоже, не было никаких разногласий по поводу предполагаемой семантики и того, что текущее имя для этой категории значений указателей плохо подходит для этого сценария.
ТК
@ ММ Я думаю, что a + 1это не определено, и, возможно, полученное значение указателя будет называться «указатель за концом». Я не говорю, что ответ неправильный. Это немного не точно, потому что это можно понять как длительное обсуждение с консенсусом, что достаточно просто указать, что результатом является «указатель на конец», чтобы решить проблему. Проблема с «указателем за концом» состоит в том, что он находится за концом некоторого объекта, и вычитание 1из такого значения указателя дает один указатель на объект, что, вероятно, не должно иметь место для массивов 0элементов.
Языковой адвокат
2
@Bathsheba Как вы думаете, может быть что-нибудь более авторитетное в неправильной формулировке?
Языковой адвокат