Почему new(nothrow) не работает в VS Code?

Я написал следующий код на 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.

VScode не является компилятором. Укажите компилятор и версию, которую вы используете.

user12002570 26.08.2024 14:04

Visual Studio Code — это редактор, а не компилятор и компоновщик, генерирующий исполняемый файл программы. Какой компилятор вы используете? Каков полный и законченный результат при сборке и запуске? Пожалуйста, отредактируйте свой вопрос, скопировав его как текст. Также включите введенные вами данные, что вы подразумеваете под «большим целым числом»?

Some programmer dude 26.08.2024 14:05

Какое значение введено для «... когда я ввожу большое целое значение для n ...»? У вас есть столько виртуальной памяти? Компилятор программы 32-битный или 64-битный?

Richard Critten 26.08.2024 14:14

Какой компилятор вы используете? Какая версия? Какие флаги компилятора? Какой стандарт С++? Какая платформа?

Eljay 26.08.2024 14:16

Связано: stackoverflow.com/questions/7555138/…

Peter 26.08.2024 14:37

@user12002570 user12002570 Я использую компилятор GCC C++ (g++) и отладчик GDB из mingw-w64.

Fancy Nancy 26.08.2024 14:52

@Jabberwocky выведет give n :

Fancy Nancy 26.08.2024 14:56

@RichardCritten Он 64-битный, и я ввожу значение 1000000000000000 для целого числа n

Fancy Nancy 26.08.2024 14:58

@Eljay Здравствуйте, я отредактировал вопрос. Я использую g++ mingw-w64. Извините, я не знаю, что такое флаги компилятора, я новичок в программировании.

Fancy Nancy 26.08.2024 15:00

@Someprogrammerdude Здравствуйте, я отредактировал вопрос, чтобы получить больше информации о моей проблеме :)

Fancy Nancy 26.08.2024 15:02

@Jabberwocky Здравствуйте, проблема в том, что я хочу, чтобы программа обнаружила, что выделение динамической памяти не удалось, если пользователь дает такое огромное число для целого числа n

Fancy Nancy 26.08.2024 15:09

Если я запускаю код в VScode с компилятором g++, этот вывод никогда не отображается. -- Во-первых, не используйте std::cin для ввода значения - вместо этого задайте n целочисленное значение, которое вы используете. Во-вторых, какую именно версию g++ вы используете? Вы получите версию g++ --version. Сейчас вашу ошибку невозможно повторить.

PaulMcKenzie 26.08.2024 15:19

Возможно, это поможет: stackoverflow.com/a/2497191/898348

Jabberwocky 26.08.2024 15:20

Возможно, исключение выдается из-за того, что размер массива выходит за пределы допустимого диапазона (отрицательный или превышает максимальный размер массива, определенный реализацией), а не из-за фактического исчерпания памяти или адресного пространства. Реализация может рассматривать это как ошибку недопустимого аргумента, а не ошибку выделения (хотя исключение по-прежнему наследуется от std::bad_alloc...), но я не думаю, что это соответствует требованиям.

François Andrieux 26.08.2024 15:23

Вы пытались распечатать? 1000000000000000 не вписывается в длинные окна.

Marc Glisse 26.08.2024 15:28
long int n; -- Если sizeof(long int) равно 4, то возникает проблема с попыткой запихнуть 10 фунтов картофеля в 5-фунтовый мешок задолго до того, как будут сделаны какие-либо вызовы new[].
PaulMcKenzie 26.08.2024 15:29

Небольшой момент: long int всегда пишется просто long. Они означают одно и то же.

Pete Becker 26.08.2024 15:34

Совет по написанию примера кода: вместо того, чтобы запрашивать ввод и объяснять, как он должен выглядеть, просто инициализируйте переменную в коде: long n = whatever;. Это исключает любые недоразумения и облегчает выполнение кода другими людьми.

Pete Becker 26.08.2024 15:37

@PaulMcKenzie Привет, спасибо за ваш комментарий. Версия: g++.exe (MinGW.org GCC Build-2) 9.2.0. Я хочу использовать std::cin, потому что работаю над кодом, который нам посоветовал написать наш профессор. Где нам нужно создать динамические массивы длиной n. int n будет присвоено значение (пользователем), и если память не может быть выделена, программа должна сообщить пользователю, что выделение памяти не удалось, а затем завершить работу.

Fancy Nancy 26.08.2024 15:55

@FrançoisAndrieux Спасибо за ваш комментарий. Что мне написать? Мне нужно, чтобы программа выдавала исключение, когда целочисленное значение n (заданное пользователем) является очень большим числом. Так что выделить необходимую память в куче не получится.

Fancy Nancy 26.08.2024 16:06

@PaulMcKenzie Так что мне написать? Мне нужно, чтобы программа выдавала исключение, когда целочисленное значение n (заданное пользователем) является очень большим числом. Так что выделить необходимую память в куче не получится. Сможет ли new (nothrow) int[n] это сделать?

Fancy Nancy 26.08.2024 16:11

@FancyNancy — Если приложение 32-битное или, более того, если long int 32-битное, оно не может иметь значение 1000000000000000. Это слишком велико, чтобы уместиться в 32-битное целое число. Если long int 32-битный, то возможно, что n — какое-то странное значение (возможно, отрицательное), и это причина, по которой все работает не так, как вы ожидаете. Если вы хотите гарантировать, что n является 64-битным, объявите его как uint64_t, а не long int. Но даже в этом случае вам необходимо убедиться, что приложение является 64-битным, а не 32-битным.

PaulMcKenzie 26.08.2024 17:41

Невозможно воспроизвести godbolt.org/z/KWhrr9W6z , но можно воспроизвести в 32-битном приложении godbolt.org/z/KWhrr9W6z Итак, ваша проблема — целочисленное переполнение — неопределенное поведение.

3CxEZiVlQ 26.08.2024 18:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
23
139
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Из как будто правило

У нового-выражения есть еще одно исключение из правила «как если бы»: компилятор может удалять вызовы заменяемых функций выделения, даже если предусмотрена определяемая пользователем замена и имеет наблюдаемые побочные эффекты.

Итак, мы можем считать, что 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, и этот ответ объясняет, почему в других случаях они могут не получать выходные данные, что, похоже, не соответствует...

Marc Glisse 26.08.2024 14:58
Ответ принят как подходящий

Вы не можете рассчитывать на 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.

Спасибо!!! Мне это очень помогло :)

Fancy Nancy 26.08.2024 17:06

Если вы используете 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).

Jarod42 26.08.2024 20:26

До C++11 для передачи отрицательного размера массива было неопределенное поведение. В C++11 и более поздних версиях он должен выдавать или возвращать nullptr в случае nothrow new. Возможно, OP компилируется для C++98.

François Andrieux 26.08.2024 20:32

Другие вопросы по теме