New int c что это
В C++ можно использовать различные типы объектов, которые различаются по использованию памяти. Так, глобальные объекты создаются при запуске программы и освобождаются при ее завершении. Локальные автоматические объекты создаются в блоке кода и удаляются, когда этот блок кода завершает работу. Локальные статические объекты создаются перед их первым использованием и освобождаются при завершении программы.
Глобальные, а также статические локальные объекты помещаются в статической памяти, а локальные автоматические объекты размещаются в стеке. Объекты в статической памяти и стеке создаются и удаляются компилятором. Статическая память очищается при завершении программы, а объекты из стека существуют, пока выполняется блок, в котором они определены.
В дополнение к этим типам в C++ можно создавать динамические объекты . Продолжительность их жизни не зависит от того, где они созданы. Динамические объекты существуют, пока не будут удалены явным образом. Динамические объекты размещаются в динамической памяти (free store).
Для управления динамическими объектами применяются операторы new и delete .
Оператор new выделяет место в динамической памяти для объекта и возвращает указатель на этот объект.
Оператор delete получает указатель на динамический объект и удаляет его из памяти.
Выделение памяти
Создание динамического объекта:
Оператор new создает новый объект типа int в динамической памяти и возвращает указатель на него. Значение такого объекта неопределено.
Также можно инициализировать объект при создании:
Освобождение памяти
Динамические объекты будут существовать пока не будут явным образом удалены. И после завершения использования динамических объектов следует освободить их память с помощью оператора delete :
Особенно это надо учитывать, если динамический объект создается в одной части кода, а используется в другой. Например:
В функции usePtr получаем из функции createPtr указатель на динамический объект. Однако после выполнения функции usePtr этот объект автоматически не удаляется из памяти (как это происходит в случае с локальными автоматическими объектами). Поэтому его надо явным образом удалить, использовав оператор delete.
Использование объекта по указателю после его удаления или повторное применение оператора delete к указателю могут привести к непредсказуемым результатам:
Поэтому следует удалять объект только один раз.
Также нередко имеет место ситуация, когда на один и тот же динамический объект указывают сразу несколько указателей. Если оператор delete применен к одному из указателей, то память объекта освобождается, и по второму указателю этот объект мы использовать уже не сможем. Если же после этого ко второму указателю применить оператор delete, то динамическая память может быть нарушена.
В то же время недопустимость указателей после применения к ним оператора delete не означает, что эти указатели мы в принципе не сможем использовать. Мы сможем их использовать, если присвоим им адрес другого объекта:
Здесь после удаления объекта, на который указывает p1, этому указателю передается адрес другого объекта в динамической памяти. Соответственно мы также можем использовать указатель p1. В то же время адрес в указателе p2 по прежнему будет недействительным.
Что означает *new int?
Есть ли способ избежать утечки памяти без изменения кода в строке (*)? Если да, то как? Если нет, то почему?
Чего я не понимаю, так это того, что означает *new int ? В частности, что означает добавление * рядом с новым?
Кроме того, что, если вместо int z у нас есть int &z ?
4 ответа
Эта строка является утечкой памяти. Также не имеет смысла когда-либо выделять int int в куче и разыгрывать его (с помощью * ) перед сохранением его дескриптора (адрес, возвращаемый new ). Таким образом, единственный возможный способ избежать утечки:
Есть ли способ избежать утечки памяти без изменения кода в строке (*)?
В реальной жизни вы бы абсолютно изменили эту линию — это безумие.
Если предположить, что это интеллектуальное упражнение, то возможны следующие варианты:
- Добавьте return; перед ним, чтобы new никогда не возникало;
- Переопределите ::operator new , чтобы вернуть указатель, к которому вы можете получить доступ другими способами, такими как глобальная переменная.
Чего я не понимаю, так это того, что означает *new int ?
new int динамически выделяет объект типа int и дает указатель на него. * разыменовывает этот указатель, чтобы объект можно было скопировать для инициализации z . Указатель нигде не хранится, поэтому впоследствии нет возможности получить доступ к динамическому объекту или удалить его.
Кроме того, инициализация z из значения неинициализированного объекта приводит к неопределенному поведению.
Кроме того, что, если вместо int z у нас будет int &z ?
z будет ссылкой на динамический объект, а не его копией. Тогда можно было бы исправить утечку с помощью delete &z . Это было бы однообразным и запутанным поступком; не делайте этого в реальном коде.
В общем, избегайте динамического выделения и, когда это необходимо, управляйте динамическими ресурсами с помощью типов RAII, таких как контейнеры и интеллектуальные указатели. Необработанные указатели подвержены ошибкам, особенно при возникновении исключений; все остальное — рецепт безумия.
Нет, с этим кодом невозможно избежать утечки памяти, поскольку указатель, возвращаемый new , теряется.
*new int означает «выделить память для int , в результате чего появится указатель на эту память, затем разыменовать указатель, получив (неинициализированный) сам int «. Я думаю, что это неопределенное поведение.
Динамическая память
В предыдущих разделах вся необходимая память определялась перед выполнением программы путем определения необходимых переменных. Но бывают случаи, когда потребности в памяти могут быть определены только во время выполнения программы. Например, когда количество памяти зависит от ввода пользователя. В таких случаях, программа должна выделять память динамически, для чего в языке C++ имеются операторы new и delete.
Операторы new и new[ ]
Динамическая память выделяется оператором new, за которым следует спецификатор типа данных и, если требуется последовательность из более, чем одного элемента, их количество в квадратных скобках [ ]. Он возвращает указатель на начало блока выделенной памяти. Его синтаксис:
pointer = new type
pointer = new type [число_элементов]
Первое выражение используется для выделения памяти для хранения одного элемента типа type. Второе используется для выделения блока(массива) элементов типа type, где число_элементов является целочисленным значением, представляющим количество элементов. Например:
В этом случае система динамически выделяет пространство для пяти элементов типа int и возвращает указатель на первый элемент последовательности, который присваивается переменной foo (указатель). Следовательно, foo сейчас указывает на валидный блок памяти с пространством для пяти элементов типа int.

Здесь foo — это указатель, и таким образом, доступ к первому элементу foo можно получить либо выражением foo[0], либо выражением *foo ( они равнозначны). Доступ ко второму элементу можно получить с помощью foo[1] или *( foo+1), и так далее.
Есть существенная разница между объявлением нормального массива и выделением динамической памяти для блока памяти с помощью new. Самое главное отличие заключается в том, что размер обычного массива должен быть константным выражением и, следовательно, ее размер должен быть определен в момент разработки программы, до ее запуска, а динамическое распределение памяти в исполнении new позволяет выделять память во время выполнения, используя любое значение переменной как размер.
Динамическая память, запрошенная нашей программой у системы, выделяется из кучи (heap). Однако компьютерная память имеет ограниченный ресурс, и он может быть исчерпан. Поэтому нет никаких гарантий, что все запросы на выделение памяти с помощью оператора new, будут удовлетворены системой.
C++ предоставляет два стандартных механизма для проверки успешности выделения памяти:
Первый — это обработка исключений. Если память выделить не удалось, выбрасывается исключение типа bad_alloc. Если не перехватить исключение, приложение завершится с ошибкой. Этот метод используется по умолчанию для new и он используется для выражений типа:
Другой метод известен как nothrow. В этом случае вместо выбрасывания исключения или выхода из программы, new возвращает null pointer, и программа продолжает нормально выполняться (на практике оказывается, что исключение все равно может выбрасываться — прим. переводчика).
Этот метод может быть описан путем использования специального объекта nothrow, определенного в заголовочном файле <new>, как аргумента для new:
Этот метод обычно создает менее эффективный код, чем перехват исключений, потому что предусматривает явную проверку значения указателя после каждого выделения памяти. Следовательно, механизм исключений обычно предпочтительнее хотя бы для критических участков кода. Большинство примеров кода будут использовать механизм nothrow ввиду его простоты.
Следует отметить случай, когда желательно, чтобы объект класса, размещенный в динамической памяти, уничтожался, а при создании нового объекта того же класса, он размещался в том же участке памяти, что и предыдущий объект, при этом повторное выделение памяти не требуется. Рассмотрим пример:
В этом примере выделяется память по адресу ptr для хранения одного объекта типа A, затем, при помощи специального синтаксиса оператора new, объект pobj типа A размещается по адресу ptr. Объекты, размещенные в памяти подобным образом, требуют уничтожения путем явного вызова деструктора объекта. После того, как первый объект уничтожен, выделенная память все еще доступна для дальнейшего использования. Далее таким же образом и по тому же адресу размещается объект pobj2, после чего он также уничтожается аналогичным образом. Перед выходом из программы, выделенная память освобождается вызовом оператора delete[] (см. следующий параграф). Можно заметить, что память выделяется и освобождается единожды, однако имеется возможность повторного использования участка памяти разными объектами, что подтверждается выводом этой программы:
ctor: 1
dtor: 1
ctor: 2
dtor: 2
Операторы delete и delete[ ]
В большинстве случаев, динамически выделенная память нужна в течение определенного периода времени. В тот момент, когда память больше не нужна, она может быть освобождена для того, чтобы она стала доступной для новых запросов. Для этой цели существует оператор delete[ ]:
Первое выражение освобождает память, выделенную при мощи new для одного элемента. Второе выражение освобождает память, выделенную для массива элементов с использованием new[ ].
Значение, переданное delete как аргумент, должно быть любым указателем на блок памяти, выделенной с помощью new, или null pointer (в этом случае delete не делает ничего).
Заметьте, что значение в скобках оператора new это переменное значение, введенное пользователем( i), а не константное выражение:
Всегда существует возможность того, что пользователь введет значение для i настолько большое, что система не сможет выделить достаточно памяти. Например, при попытке выделить память для биллиона элементов, система может не выделить достаточно памяти.
Считается хорошей практикой всегда обрабатывать ошибки при выделении памяти обработкой соответствующего исключения или проверкой значения указателя.
Динамическая память в C
C++ включает операторы new и delete для динамического выделения памяти, однако это не относится к языку C. Вместо них используются библиотечные функции malloc, calloc, realloc и free, определенные в <cstdlib> или <stdlib.h> в языке C. Эти функции также доступны и в C++ и могут быть использованы для выделения и освобождения памяти.
Однако блоки памяти, выделенные этими функциями, не обязательно совместимы с теми, которые возвращает оператор new, поэтому не нужно их смешивать; каждый из них должен быть обработан собственным набором функций или операторов.