Свойства указателя на массив нулевой длины - PullRequest
21 голосов
/ 28 февраля 2020

Рассмотрим

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

В промежутке между инициализацией и удалением копии вам разрешено читать указатель на a + 1?

Кроме того, позволяет ли язык компилятору установить a до nullptr?

Ответы [ 2 ]

23 голосов
/ 28 февраля 2020

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

Из этого следует, что a не может быть нулевым, а a + 1 не определяется [expr.add] / 4 .

3 голосов
/ 14 марта 2020
    auto a = new int[0];

Согласно [basi c .compound.3] значение, хранимое в a, должно быть одним из следующих:

  1. Указатель на объект (типа int)
  2. Указатель за концом объекта
  3. Нуль
  4. Недопустимый

Мы можем исключить первую возможность, поскольку не было построено объектов типа int. Третья возможность исключена, поскольку C ++ требует, чтобы возвращался ненулевой указатель (см. [basi c .st c .dynami c .allocation.2] ). Таким образом, у нас остается две возможности: указатель за концом объекта или недопустимый указатель.

Я был бы склонен рассматривать a как указатель конца конца, но я не имеют авторитетную ссылку на окончательно установить sh, что. (Тем не менее, это имеет сильное значение в [basi c .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?

Нет. Из вышеупомянутого [basi c .st c .dynami c .allocation.2] : "Если запрос завершается успешно, значение, возвращаемое заменяемой функцией распределения, равно ненулевое значение указателя ". Существует также сноска , в которой говорится, что C ++ (но не C) требует ненулевого указателя в ответ на нулевой запрос.

...