Я наткнулся на тест, который включал объявление массива с различными размерами. Первое, что пришло мне в голову, это то, что мне нужно будет использовать динамическое распределение с new
командой, например так:
while(T--) {
int N;
cin >> N;
int *array = new int[N];
// Do something with 'array'
delete[] array;
}
Однако я увидел, что одно из решений допускает следующий случай:
while(T--) {
int N;
cin >> N;
int array[N];
// Do something with 'array'
}
После небольшого исследования я прочитал, что g ++ позволяет это, но это заставило меня задуматься, в каких случаях тогда необходимо использовать динамическое распределение? Или компилятор переводит это как динамическое распределение?
Функция удаления включена. Обратите внимание, однако, что вопрос здесь не об утечках памяти.
c++
arrays
dynamic-memory-allocation
static-memory-allocation
learning_dude
источник
источник
std::vector
вместо (std::vector<int> array(N);
).new OBJ
непосредственного вызова .Ответы:
Ни один фрагмент кода, который вы показываете, не является идиоматическим, современным кодом C ++.
new
иdelete
(иnew[]
иdelete[]
) не устарели в C ++ и никогда не будут. Они все еще являются способом создания динамически размещаемых объектов. Однако, поскольку вы всегда должны сопоставлять anew
сdelete
(и anew[]
с adelete[]
), лучше всего их хранить в (библиотечных) классах, которые гарантируют это для вас. См. Почему программисты на C ++ должны минимизировать использование 'new'? ,Ваш первый фрагмент использует «голый»,
new[]
а затем никогда неdelete[]
созданный массив. Это проблема.std::vector
делает все, что вам нужно здесь просто отлично. Он будет использовать некоторую скрытую формуnew
(я не буду вдаваться в детали реализации), но для всех, что вам нужно, это динамический массив, но лучше и безопаснее.Ваш второй фрагмент использует «массивы переменной длины» (VLA), функцию C, которую некоторые компиляторы также допускают в C ++ в качестве расширения. В отличие от
new
VLA, по существу, расположены в стеке (очень ограниченный ресурс). Но что более важно, они не являются стандартной функцией C ++, и их следует избегать, потому что они не переносимы. Они, конечно, не заменяют динамическое (т.е. кучное) распределение.источник
Qt
, поскольку все его базовые классы имеют сборщики мусора, поэтому вы просто используетеnew
и забываете об этом большую часть времени. Для элементов GUI, когда родительский виджет закрыт, дочерние элементы выходят из области видимости и автоматически собирают мусор.new
прежнему есть соответствиеdelete
; простоdelete
s выполняется родительским виджетом, а не в том же блоке кода, что иnew
s.Ну, для начала,
new
/delete
не осуждается.В вашем конкретном случае, они не единственное решение, хотя. То, что вы выберете, зависит от того, что скрыто под вашим комментарием "сделать что-то с массивом".
Ваш второй пример использует нестандартное расширение VLA, которое пытается разместить массив в стеке. Это имеет определенные ограничения, а именно: ограниченный размер и невозможность использования этой памяти после того, как массив выходит из области видимости. Вы не можете переместить его, он «исчезнет» после того, как стек раскрутится.
Поэтому, если ваша единственная цель - выполнить локальные вычисления, а затем выбросить данные, это может на самом деле работать нормально. Однако более надежным подходом было бы динамическое распределение памяти, предпочтительно с
std::vector
. Таким образом, вы получаете возможность создавать пространство для ровно столько элементов, сколько вам нужно, основываясь на значении времени выполнения (к чему мы стремимся все время), но оно также хорошо очищается и вы можете его убрать этой области, если вы хотите сохранить память на потом.Возвращаясь к началу, возможно ,
vector
будем использоватьnew
несколько уровней глубже, но вам не следует беспокоиться об этом, поскольку интерфейс, который он представляет, намного лучше. В этом смысле использованиеnew
иdelete
может считаться обескураженным.источник
new
иdelete
, а использовать интеллектуальные указатели, такие какstd::unique_pointer
.std::unique_ptr
std::unique_ptr
умолчанию вызываетdelete
илиdelete[]
, что означает, что принадлежащий объект должен был быть выделенnew
или вnew[]
любом случае, в какие вызовы были скрытыstd::make_unique
начиная с C ++ 14.Ваши вторые примеры используют массивы переменной длины (VLA), которые фактически являются функцией C99 ( не C ++!), Но тем не менее поддерживаются g ++ .
Смотрите также этот ответ .
Обратите внимание, что массивы переменной длины отличаются от
new
/delete
и никоим образом не "осуждают" их.Также имейте в виду, что VLA не являются ISO C ++.
источник
Современный C ++ предоставляет более простые способы работы с динамическими распределениями. Умные указатели могут позаботиться об очистке после исключений (которые могут произойти где угодно, если это разрешено) и ранних возвратов, как только указанные структуры данных выйдут из области видимости, поэтому может иметь смысл использовать их вместо этого:
С C ++ 14 вы также можете написать
это выглядит еще лучше и предотвратит утечку памяти в случае сбоя выделения. С C ++ 20 вы должны быть в состоянии сделать столько, сколько
это для меня все еще не компилируется во время написания с gcc 7.4.0. В этих двух примерах мы также используем
auto
вместо объявления типа слева. Во всех случаях используйте массив как обычно:Утечки памяти
new
и сбои при дублированииdelete
- это то, что C ++ было разбито на протяжении многих лет, являясь «центральной точкой» аргументации для перехода на другие языки. Может быть, лучше избегать.источник
unique/shared_ptr
конструкторов в пользу тогоmake_unique/shared
, что вы не только не должны писать составной тип дважды (используяauto
), но и не рискуете потерять память или ресурсы, если построение завершится неудачей частично (если вы используете тип, который может дать сбой)make_shared<int[]>
много пользуюсь , когда ты всегда хочешьvector<int>
, но приятно знать.unique_ptr
конструктор nothrow, поэтому дляT
которых есть nothrow конструкторов, так что нет никакого риска утечки сunique_ptr(new int[size])
иshared_ptr
имеет следующее: «Если исключение, удаление р называется , когда T не является тип массива, удаление [ ] p в противном случае. ", так что вы имеете тот же эффект - риск дляunique/shared_ptr(new MyPossiblyAllocatingType[size])
.новые и удалить не становятся устаревшими.
Объекты, созданные новым оператором, могут быть переданы по ссылке. Объекты могут быть удалены с помощью удаления.
new и delete являются основополагающими аспектами языка. Постоянство объекта может управляться с помощью new и delete. Это определенно не будет устаревшим.
Утверждение - int array [N] - это способ определения массива. Массив может использоваться в пределах объема кодового блока. Он не может быть передан подобно тому, как объект передается другой функции.
источник
Первый пример нуждается
delete[]
в конце, иначе у вас будет утечка памяти.Во втором примере используется переменная длина массива, которая не поддерживается C ++; это позволяет только константное выражение для длины массива .
В этом случае это полезно использовать в
std::vector<>
качестве решения; это оборачивает все действия, которые вы можете выполнить над массивом, в класс шаблона.источник
Синтаксис выглядит как C ++, но идиома похожа на обычный старый Algol60. Было принято иметь такие блоки кода:
Пример можно записать так:
Я иногда скучаю по этому на современных языках;)
источник