Почему я получаю Invalid Allocation Size: 4294967295 Bytes вместо исключения std::bad_alloc?

Я написал следующий фрагмент кода для выделения памяти для массива:

try {
    int n = 0;
    cin >> n;
    double *temp = new double[n];
    ...
}
catch(exception& e) {
    cout << "Standard exception: " << e.what() << endl;
    exit(1);
}

Конечно, я проверяю n на наличие отрицательных значений и т. д., но когда я ввожу какое-то большое число больше 536 * (10 ^ 6), я получаю не исключение bad-alloc, а сбой «Недопустимый размер выделения: 4294967295 байт».

НАПРИМЕР. Я ввожу n = 536*(10^6) --> исключение bad-alloc Я ввожу n = 537*(10^6) --> Недопустимый размер выделения: 4294967295 байт --> Сбой

Есть идеи, почему это происходит?


person StarFighter    schedule 05.05.2014    source источник
comment
Вы уверены, что хотите выделить 4 ГБ?   -  person Lightness Races in Orbit    schedule 05.05.2014
comment
работает в 32-битном или 64-битном процессе?   -  person MatthiasB    schedule 05.05.2014
comment
Я не всегда хочу выделять столько памяти, но я не хочу, чтобы моя программа вылетала, если она попытается... Процессор - Intel E8400 с 4 ГБ ОЗУ и 64-разрядной версией Win7. Я вижу, что у меня недостаточно памяти, но я не понимаю, почему это не дает мне исключение bad-alloc.   -  person StarFighter    schedule 05.05.2014
comment
Я думаю, что @MatthiasB и @ Lightness Races in Orbit пытаются вам сказать, что вы, вероятно, пытаетесь выделить много памяти, либо больше, чем есть в системе, либо больше, чем может поддерживать ОС / ЦП.   -  person in need of help    schedule 05.05.2014
comment
Вы уверены, что это 536*(10^6), а не 536*(10^7)? Вы можете позвонить cout<<n после cin>>n, чтобы убедиться в этом?   -  person barak manos    schedule 05.05.2014
comment
@barak Да, я сделал cout ‹‹ n перед выделением памяти. Целое верно. Когда я ввожу числа › размером с целое число, моя программа просто останавливается, потому что n отрицательно.   -  person StarFighter    schedule 05.05.2014
comment
Я отредактировал заголовок вопроса, чтобы сделать его более понятным, надеюсь, что это поможет.   -  person Daniel Daranas    schedule 05.05.2014
comment
Ах да, конечно - это double вы выделяете, вот почему. 536*(10^6) * sizeof(double) превышает 4294967295.   -  person barak manos    schedule 05.05.2014
comment
См. также этот связанный вопрос.   -  person Daniel Daranas    schedule 05.05.2014


Ответы (3)


Вызов new double[n] вызывает глобальную функцию operator new с размером n * sizeof(double). Если затем operator new обнаруживает, что не может выполнить запрос, выдается исключение.

Однако здесь этого не может быть: произведение n и sizeof(double) настолько велико, что на самом деле вообще невозможно вызвать operator new, потому что запрошенный вами размер просто не помещается в size_t. Реализации различаются тем, как они справляются с этим, но ваша, очевидно, прерывает программу.

Если вы хотите справиться с этим, вы можете проверить это n <= SIZE_MAX / sizeof(double) перед попыткой выделения.

person Community    schedule 05.05.2014
comment
Спасибо за этот прекрасный ответ, теперь я понял, почему он падает, а не выдает исключение. - person StarFighter; 05.05.2014
comment
Я не могу найти ссылку на это в стандарте. Если вы знаете такой, не могли бы вы поделиться им? Я также не могу воспроизвести это поведение, я получаю bad_alloc независимо от того, насколько велико число. - person jrok; 05.05.2014
comment
@jrok В стандарте не было определено поведение до C++11, поэтому разрешалось любое поведение (open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#256). Он изменился в C++11 (open-std. org/jtc1/sc22/wg21/docs/cwg_defects.html#624, open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#805), чтобы было выдано исключение (у меня возникли проблемы с поиском ссылки в стандарт), но того факта, что этого не происходит, достаточно, чтобы показать, что OP не использует реализацию, соответствующую С++ 11. - person ; 05.05.2014
comment
@jrok Ах, сначала неправильно прочитал, но все равно нашел. В C++11 это 5.3.4p7: если значение этого выражения меньше нуля или таково, что размер выделенного объекта превысит ограничение, определенное реализацией, или [... ], хранилище не получено, и new-expression завершается выдачей исключения типа, который соответствует обработчику (15.3) типа std::bad_array_new_length (18.6.2.2). - person ; 05.05.2014

Если вы используете Visual Studio для сборки, вы можете включить «большое выделение памяти» в настройках компоновщика.

Перейдите в «Свойства проекта» -> «Компоновщик» -> «Система» -> «Включить большие адреса» и установите значение «Да (/LARGEADDRESSAWARE)».

person Martin Perry    schedule 05.05.2014

В 32-разрядной системе адресное пространство виртуальной памяти не может превышать 2^31-1 (4294967295) байт.

Вы пытаетесь выделить 536000000*sizeof(double) байт, что явно больше.

person barak manos    schedule 05.05.2014
comment
Это не объясняет, почему он не выдает bad_alloc, что является исключением, когда вы пытаетесь выделить больше памяти, чем доступно. - person Barmar; 05.05.2014
comment
@Barmar: выдает недопустимый размер выделения: 4294967295 байт, что имеет смысл, учитывая размер выделения. - person barak manos; 05.05.2014
comment
Это имеет смысл, но это не то, что говорит ваш ответ. В вашем ответе говорится, что это не удается, потому что вы пытаетесь превысить пространство виртуальной машины. Кстати, я думаю, что во втором предложении пропущено слово после того, как очевидно. - person Barmar; 05.05.2014