Подтвердить что ты не робот

Почему новый [-1] генерирует segfault, а новый [-2] бросает bad_alloc?

Я попытался протестировать исключение bad_alloc, передав некоторые отрицательные аргументы в new[]. При прохождении небольших отрицательных чисел я получаю то, на что я надеялся - a bad_alloc. Однако при передаче -1 я вижу, что мой объект построен тысячи раз (я печатаю статический счетчик в конструкторе), и приложение завершается с помощью segfault.

new[] преобразует целое число со знаком в size_t, поэтому -1 является максимальным значением size_t и -2 является maximum - 1 и т.д.

Итак, почему new[] выдает исключение при получении некоторого огромного количества, но пытается выделить при получении max size_t? В чем разница между 1111...1 и 1111...0 для new[]?:)

Спасибо заранее!

4b9b3361

Ответ 1

Здесь мое дикое предположение:

Во множестве реализаций распределитель разместит некоторые метаданные рядом с выделенной областью.
(Например, размер выделения.) Таким образом, вы фактически выделяете больше, чем вы просили.

Предположим, что size_t - 32 бит. Скомпилирован для 32-разрядных.


Когда вы выполните:

int *array = new int[-1];

-1 становится -1 * 4 bytes = 4294967292 (после переполнения). Но если реализация распределителя помещает 4 байта метаданных рядом с выделенной областью. Фактический размер будет:

4294967292 + 4 bytes = 0 bytes (after overflow)

Таким образом, фактически выделяется 0 байт.

Когда вы пытаетесь получить доступ к памяти, вы segfault, так как сразу выходите за пределы.


Теперь скажите, что вы делаете:

int *array = new int[-2];

-2 становится -2 * 4 bytes = 4294967288 (после переполнения). Добавьте 4 байта метаданных и получите 4294967288 + 4 = 4294967292.

Когда распределитель запрашивает 4294967292 байты из ОС, он отказывается. Поэтому он бросает bad_alloc.


В принципе, возможно, что -1 и -2 делает разницу между тем, будет ли он переполняться после того, как распределитель добавит свои метаданные.