Я написал следующий код на VScode C++.
Когда я ввожу действительно большое целое число для n (например, 1000000000000000), я хочу получить следующий результат:
"Dynamic memory allocation failed.\nProgram will terminate."
Если я запускаю код в VScode с компилятором g++, этот вывод никогда не отображается.
Однако, когда я запускаю его в онлайн-компиляторе, таком как Programiz, отображается нужный мне результат.
Программа следующая:
#include <iostream>
#include <new>
int main(){
long int n;
std::cout << "give n : ";
std::cin >> n;
int* a= new (std::nothrow) int[n]; // I expect new to return nullptr
// if the allocation fails
if (!a) {
std::cout << "Dynamic memory allocation failed.\nProgram will terminate.";
return -1;
}
return 0;
}
Так в чем же проблема?
Как я уже сказал, в онлайн-компиляторе, когда я ввожу, например, 1000000000000000 в качестве значения целого числа n, результат будет желаемым:
give n : 1000000000000000
Dynamic memory allocation failed.
Program will terminate.
=== Code Exited With Errors ===
но в VScode вывод:
if ($?) { g++ test.cpp -o test } ; if ($?) { .\test }
give n : 1000000000000000
terminate called after throwing an instance of 'std::bad_array_new_length'
what(): std::bad_array_new_length
Что я могу сделать, чтобы это исправить?
проблема в том, что я хочу, чтобы программа обнаружила, что выделение динамической памяти не удалось, если пользователь дает такое огромное число для целого числа n
Я использую компилятор GCC C++ (g++) и отладчик GDB из mingw-w64.
Я скачал VScode версии 1.92 и следовал инструкциям с их сайта https://code.visualstudio.com/docs/cpp/config-mingw.
Visual Studio Code — это редактор, а не компилятор и компоновщик, генерирующий исполняемый файл программы. Какой компилятор вы используете? Каков полный и законченный результат при сборке и запуске? Пожалуйста, отредактируйте свой вопрос, скопировав его как текст. Также включите введенные вами данные, что вы подразумеваете под «большим целым числом»?
Какое значение введено для «... когда я ввожу большое целое значение для n ...»? У вас есть столько виртуальной памяти? Компилятор программы 32-битный или 64-битный?
Какой компилятор вы используете? Какая версия? Какие флаги компилятора? Какой стандарт С++? Какая платформа?
Связано: stackoverflow.com/questions/7555138/…
@user12002570 user12002570 Я использую компилятор GCC C++ (g++) и отладчик GDB из mingw-w64.
@Jabberwocky выведет give n :
@RichardCritten Он 64-битный, и я ввожу значение 1000000000000000 для целого числа n
@Eljay Здравствуйте, я отредактировал вопрос. Я использую g++ mingw-w64. Извините, я не знаю, что такое флаги компилятора, я новичок в программировании.
@Someprogrammerdude Здравствуйте, я отредактировал вопрос, чтобы получить больше информации о моей проблеме :)
@Jabberwocky Здравствуйте, проблема в том, что я хочу, чтобы программа обнаружила, что выделение динамической памяти не удалось, если пользователь дает такое огромное число для целого числа n
Если я запускаю код в VScode с компилятором g++, этот вывод никогда не отображается. -- Во-первых, не используйте std::cin для ввода значения - вместо этого задайте n целочисленное значение, которое вы используете. Во-вторых, какую именно версию g++ вы используете? Вы получите версию g++ --version. Сейчас вашу ошибку невозможно повторить.
Возможно, это поможет: stackoverflow.com/a/2497191/898348
Возможно, исключение выдается из-за того, что размер массива выходит за пределы допустимого диапазона (отрицательный или превышает максимальный размер массива, определенный реализацией), а не из-за фактического исчерпания памяти или адресного пространства. Реализация может рассматривать это как ошибку недопустимого аргумента, а не ошибку выделения (хотя исключение по-прежнему наследуется от std::bad_alloc...), но я не думаю, что это соответствует требованиям.
Вы пытались распечатать? 1000000000000000 не вписывается в длинные окна.
long int n; -- Если sizeof(long int) равно 4, то возникает проблема с попыткой запихнуть 10 фунтов картофеля в 5-фунтовый мешок задолго до того, как будут сделаны какие-либо вызовы new[].
Небольшой момент: long int всегда пишется просто long. Они означают одно и то же.
Совет по написанию примера кода: вместо того, чтобы запрашивать ввод и объяснять, как он должен выглядеть, просто инициализируйте переменную в коде: long n = whatever;. Это исключает любые недоразумения и облегчает выполнение кода другими людьми.
@PaulMcKenzie Привет, спасибо за ваш комментарий. Версия: g++.exe (MinGW.org GCC Build-2) 9.2.0. Я хочу использовать std::cin, потому что работаю над кодом, который нам посоветовал написать наш профессор. Где нам нужно создать динамические массивы длиной n. int n будет присвоено значение (пользователем), и если память не может быть выделена, программа должна сообщить пользователю, что выделение памяти не удалось, а затем завершить работу.
@FrançoisAndrieux Спасибо за ваш комментарий. Что мне написать? Мне нужно, чтобы программа выдавала исключение, когда целочисленное значение n (заданное пользователем) является очень большим числом. Так что выделить необходимую память в куче не получится.
@PaulMcKenzie Так что мне написать? Мне нужно, чтобы программа выдавала исключение, когда целочисленное значение n (заданное пользователем) является очень большим числом. Так что выделить необходимую память в куче не получится. Сможет ли new (nothrow) int[n] это сделать?
@FancyNancy — Если приложение 32-битное или, более того, если long int 32-битное, оно не может иметь значение 1000000000000000. Это слишком велико, чтобы уместиться в 32-битное целое число. Если long int 32-битный, то возможно, что n — какое-то странное значение (возможно, отрицательное), и это причина, по которой все работает не так, как вы ожидаете. Если вы хотите гарантировать, что n является 64-битным, объявите его как uint64_t, а не long int. Но даже в этом случае вам необходимо убедиться, что приложение является 64-битным, а не 32-битным.
Невозможно воспроизвести godbolt.org/z/KWhrr9W6z , но можно воспроизвести в 32-битном приложении godbolt.org/z/KWhrr9W6z Итак, ваша проблема — целочисленное переполнение — неопределенное поведение.





У нового-выражения есть еще одно исключение из правила «как если бы»: компилятор может удалять вызовы заменяемых функций выделения, даже если предусмотрена определяемая пользователем замена и имеет наблюдаемые побочные эффекты.
Итак, мы можем считать, что int* a = new (std::nothrow) int[n]; всегда добивается успеха.
в результате программа
int main(){
long int n;
std::cout << "give n : ";
std::cin >> n;
}
Вы можете увидеть здесь, что clang оптимизирует выделение (и не выводит сообщение), тогда как gcc не оптимизирует и не выполняет вызов и поэтому не печатает сообщение.
Вопрос спрашивает, почему в некоторых случаях они получают bad_array_new_length, и этот ответ объясняет, почему в других случаях они могут не получать выходные данные, что, похоже, не соответствует...
Вы не можете рассчитывать на new возврат nullptr, если распределение пойдет не так, по крайней мере, на недавние реализации C++, совместимые со стандартами (неясно, какой стандарт на самом деле), и (std::nothrow), по-видимому, не имеет никакого влияния на вашу реализацию.
Вместо этого вам следует перехватывать и обрабатывать исключения следующим образом:
#include <iostream>
#include <new>
int main() {
long int n = 1000000000000000;
int* a;
try
{
a = new int[n];
}
catch(...)
{
// if the allocation fails
std::cout << "Dynamic memory allocation failed.\nProgram will terminate.\n";
return -1;
}
// do something with a
delete [] a;
return 0;
}
Другая возможность, возможно, более удобная для вашего случая использования, — использование std::set_new_handler:
#include <iostream>
#include <new>
#include <cstdlib>
void newhandler()
{
std::cout << "Dynamic memory allocation failed.\nProgram will terminate.\n";
exit(-1);
return;
}
int main() {
std::set_new_handler(newhandler);
long int n = 1000000000000000;
int *a = new int[n]; // I expect new to return nullptr
// do something with a;
delete [] a;
return 0;
}
Как только new пойдет не так, будет вызван newhandler(), который позаботится о отображении вашего сообщения об ошибке, а затем завершит работу с использованием функции exit.
Спасибо!!! Мне это очень помогло :)
Если вы используете Windows, то long int n — это 32-битное целое значение или вы создаете 32-битное приложение на других платформах. Когда вы вводите 1000000000000000, вы получаете целочисленное переполнение и отрицательное значение -1530494976 в n. new int[n] с отрицательным значением выбрасывает std::bad_array_new_length. Обратите внимание: это исключение не отключается при перегрузке std::nothrowoperator new.
https://godbolt.org/z/sf4GKszKd
Обновите декларацию long long n или uint64_t n после #include <cstdint>.
Компилятор имеет ограничение на выделение Демо для gcc: «размер массива '2147483648' превышает максимальный размер объекта '2147483647'» (2147483647 — это 0x7FFF'FFFF).
До C++11 для передачи отрицательного размера массива было неопределенное поведение. В C++11 и более поздних версиях он должен выдавать или возвращать nullptr в случае nothrow new. Возможно, OP компилируется для C++98.
VScode не является компилятором. Укажите компилятор и версию, которую вы используете.