delete [] предоставил измененный новый указатель. Неопределенное поведение? - PullRequest
5 голосов
/ 25 апреля 2009

Я видел некоторый код, показанный ниже, во время сеанса рецензирования кода:

char *s = new char[3];
*s++ = 'a';
*s++ = 'b';
*s++='\0';
delete []s; // this may or may not crash on some or any day !!

Во-первых, я знаю, что в стандарте C ++ указание на один за другим размер массива равно O.K. хотя доступ к нему приводит к неопределенному поведению. Поэтому я считаю, что последняя строка *s++='\0' в порядке. Но если я правильно помню, стандарт C ++ требует, чтобы в delete указывался тот же указатель, что и в new.

Я полагаю, это означает, что возвращаемый указатель не должен быть подделан. Я предполагаю, что это потому, что new может хранить некоторую служебную информацию до возвращаемого адреса, который может использовать delete. Перемещение указателя new может сделать это недоступным.

Это неопределенное поведение или определяемое реализацией или неуказанное? Кто-нибудь может подтвердить это, пожалуйста? Желательно, указав на правильное место в стандарте C ++.

В свободно доступной черновой версии проекта стандарта C ++ (Draft_SC22-N-4411.pdf) подробности приведены в разделе 5.3.5. Я получил это с домашней страницы Бьярне.

Ответы [ 3 ]

17 голосов
/ 25 апреля 2009

Из стандарта C ++, раздел 5.3.5 / 2:

значение операнда удаления должно быть значением указателя который возник из предыдущего массива новое выражение. Если нет, то поведение не определено

4 голосов
/ 25 апреля 2009

Да, вы должны удалить [] исходный указатель, который вы дали новым; в этом случае это будет указатель на начало массива, а не на хвост. Код здесь удаляет другой неуказанный случайный объект.

3 голосов
/ 01 мая 2009

Да, вспомните, как это часто реализуется: new действительно вызывает malloc, который возвращает указатель на (void*)(&(((int*)p)[1])), где p - фактическое начало выделенной памяти, а первое int - размер фактической памяти, которую мы вернулся.

Указатель, который мы получаем, на один размер (int) (или что-либо еще, что требуется для выравнивания) дальше в фактической выделенной памяти. Мы кладем туда наш объект, оставляя фактический размер без изменений.

Затем, когда этот указатель передается для удаления, который передает его свободному, free просматривает один int перед переданным указателем, чтобы найти размер, который возвращается.

Передача назад чего-то другого, кроме того, что мы получили, будет означать, что free думает, что произвольный объем фактической памяти возвращается назад, и это соответственно испортит свободный список.

Опять же, это то, как это часто реализуется, а не то, как требуется новое, удаление, malloc или free.

...