Для чего используется оператор new

[C++] Всё ли мы знаем об операторах new и delete?

Привет! Ниже речь пойдет об известных всем операторах new и delete, точнее о том, о чем не пишут в книгах (по крайней мере в книгах для начинающих).
На написание данной статьи меня побудило часто встречаемое заблуждение по поводу new и delete, которое я постоянно вижу на форумах и даже(. ) в некоторых книгах.
Все ли мы знаем, что такое на самом деле new и delete? Или только думаем, что знаем?
Эта статья поможет вам разобраться с этим (ну, а те, кто знают, могут покритиковать:))

Note: ниже пойдет речь исключительно об операторе new, для других форм оператора new и для всех форм оператора delete все ниженаписанное также является правдой и применимо по аналогии.

Итак, начнем с того, что обычно пишут в книгах для начинающих, когда описывают new (текст взят «с потолка», но вцелом соответствует правде):

Оператор new выделяет память больше или равную требуемому размеру и, в отличие от функций языка С, вызывает конструктор(ы) для объекта(ов), под которые память выделена… вы можете перегрузить (где-то пишут реализовать) оператор new под свои нужды.

И для примера показывают примитивную перегрузку (реализацию) оператора new, прототип которого выглядит так
void* operator new (std::size_t size) throw (std::bad_alloc);

На что хочется обратить внимание:
1. Нигде не разделяют new key-word языка С++ и оператор new, везде о них говорят как об одной сущности.
2. Везде пишут, что new вызывает конструктор(ы) для объекта(ов).
И первое и второе является распространенным заблуждением.

Но не будем надеяться на книги для начинающих, обратимся к Стандарту, а именно к разделу 5.3.4 и к 18.6.1, в которых собственно и раскрывается (точнее приоткрывается) тема данной статьи.

5.3.4
The new-expression attempts to create an object of the type-id (8.1) or new-type-id to which it is applied. /*дальше нам не интересно*/
18.6.1
void* operator new(std::size_t size) throw(std::bad_alloc);
Effects: The allocation function called by a new-expression (5.3.4) to allocate size bytes of
storage suitably aligned to represent any object of that size /*дальше нам не интересно*/

Тут мы уже видим, что в первом случае new именуется как expression, а во втором он объявлен как operator. И это действительно 2 разные сущности!
Попробуем разобраться почему так, для этого нам понадобятся ассемблерные листинги, полученные после компиляции кода, использующего new. Ну, а теперь обо все по порядку.

new-expression — это оператор языка, такой же как if, while и т.д. (хотя if, while и т.д. все же именуются как statement, но отбросим лирику) Т.е. встречая его в листинге компилятор генерирует определенный код, соответствующий этому оператору. Так же new — это одно из key-words языка С++, что еще раз подтверждает его общность с if‘ами, for’ами и т.п. А operator new() в свою очередь — это просто одноименная функция языка С++, поведение которой можно переопределить. ВАЖНОoperator new() НЕ вызывает конструктор(ы) для объекта(ов), под который(ые) выделяется память. Он просто выделяет память нужного размера и все. Его отличие от сишных функций в том, что он может бросить исключение и его можно переопределить, а так же сделать оператором для отдельно взятого класса, тем самым переопределить его только для этого класса (остальное вспомните сами:)).
А вот new-expression как раз и вызывает конструктор(ы) объекта(ов). Хотя правильней сказать, что он тоже ничего не вызывает, просто, встречая его, компилятор генерирует код вызова конструктора(ов).

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

после исполнения данного кода, как и ожидалось, будет напечатано «Foo()». Разберемся почему, для этого понадобится заглянуть в ассемблер, который я немного прокомментировал для удобства.
(код получен компилятором cl, используемым в MSVS 2012, хотя в основном я использую gcc, но это к делу не относится)

Для тех, кто ничего не понял, вот (почти) аналог того, что получилось на сиподобном псевдокоде (т.е. не надо пробовать это компилировать :))

Приведенный код подтверждает все, написанное выше, а именно:
1. оператор (языка) new и operator new() — это НЕ одно и тоже.
2. operator new() НЕ вызывает конструктор(ы)
3. вызов конструктора(ов) генерирует компилятор, встречая в коде key-word «new»

Итог: надеюсь, эта статья помогла вам понять разницу между new-expressionи operator new() или даже узнать, что она (эта разница) вообще существует, если кто-то не знал.

P.S. оператор delete и operator delete() имеют аналогичное различие, поэтому в начале статьи я сказал, что не буду его описывать. Думаю, теперь вы поняли, почему его описание не имеет смысла и сможете самостоятельно проверить справедливость написанного выше для delete.

Update:
Хабражитель с ником khim в личной переписке предложил следующий код, который хорошо демонстрирует суть написанного выше.

Источник

Оператор new (справочник по C#)

Оператор new создает экземпляр типа.

Вызов конструктора

Для создания экземпляра типа обычно вызывается один из конструкторов этого типа с помощью оператора new :

Начиная с версии C# 9.0 выражения вызова конструктора имеют целевой тип. То есть, если известен целевой тип выражения, вы можете опустить имя типа, как показано в следующем примере:

Как показано в предыдущем примере, выражение new с целевым типом всегда указывается в скобках.

Если целевой тип выражения new неизвестен (например, если вы используете ключевое слово var ), нужно указать имя типа.

создание массива

С помощью оператора new можно также создать экземпляр массива, как показано в следующем примере:

Чтобы создать экземпляр массива и заполнить его элементами в одном операторе, используйте синтаксис инициализации массива. В следующем примере показаны различные способы сделать это:

Дополнительные сведения см. в руководстве по работе с массивами.

Создание экземпляров анонимных типов

Чтобы создать экземпляр анонимного типа, используйте оператор new и синтаксис инициализации объекта:

Уничтожение экземпляров типа

Уничтожать ранее созданные экземпляры типа необязательно. Экземпляры как ссылочных типов, так и типов значений уничтожаются автоматически. Экземпляры типов значений уничтожаются, как только уничтожается содержащий их контекст. Экземпляры ссылочных типов уничтожаются сборщиком мусора в неуказанное время после удаления последней ссылки на них.

Для экземпляров типа, которые содержат неуправляемые ресурсы, например дескриптор файла, рекомендуется использовать детерминированную очистку, чтобы как можно скорее высвободить эти ресурсы. Дополнительные сведения см. в справке по API System.IDisposable и статье об операторе using.

Возможность перегрузки оператора

Спецификация языка C#

Дополнительные сведения см. в разделе Оператор newспецификация языка C#.

Подробные сведения о выражении new с целевым типом см. в примечании к предлагаемой функции.

Источник

Операторы new и delete

Список файлов библиотеки в библиотеке времени выполнения C и стандартной библиотеке C++ см. в разделе функции библиотеки CRT.

new Оператор

Компилятор преобразует инструкцию, такую как this, в вызов функции operator new :

operator new В следующей таблице описаны две области для функций.

Область действия для operator new функций

ОператорОбласть
::operator newGlobal
имя классаКласс

Глобальная operator new функция вызывается, когда new оператор используется для выделения объектов встроенных типов, объектов типа класса, которые не содержат определяемых пользователем operator new функций, и массивов любого типа. Если new оператор используется для выделения объектов типа класса, в котором operator new определен объект, operator new вызывается этот класс.

operator new Функция, определенная для класса, является статической функцией-членом (которая не может быть виртуальной), которая скрывает глобальную operator new функцию для объектов этого типа класса. Рассмотрим случай, когда new используется для выделения и установки памяти для заданного значения:

Аргумент, заданный в круглых скобках, new передается в Blanks::operator new качестве chInit аргумента. Однако глобальная operator new функция скрыта, что приводит к формированию ошибки следующим кодом:

Компилятор поддерживает массив new и операторы-члены delete в объявлении класса. Пример:

Обработка нехватки памяти

Тестирование на неудачное выделение памяти можно выполнить, как показано ниже.

Существует другой способ обработки запросов на выделение памяти, завершившихся сбоем. Напишите пользовательскую подсистему восстановления для решения такой ошибки, а затем зарегистрируйте функцию, вызвав _set_new_handler функцию времени выполнения.

delete Оператор

Память, выделенная динамически с помощью new оператора, может быть освобождена с помощью delete оператора. Оператор delete вызывает operator delete функцию, которая освобождает память в доступном пуле. Использование delete оператора также приводит к вызову деструктора класса (если он существует).

Глобальная operator delete функция. Для глобальных operator delete функций и членов класса существуют две формы operator delete :

Цель второй формы — ускорить поиск нужной категории размера объекта для удаления. Эти сведения часто не хранятся рядом с самим выделением и, скорее всего, не кэшируются. Вторая форма полезна, когда operator delete функция из базового класса используется для удаления объекта производного класса.

В следующем примере показаны определяемые пользователем operator new функции и, operator delete предназначенные для записи в журнал выделений и освобождений памяти:

Приведенный выше код можно использовать для обнаружения «утечки памяти», то есть памяти, выделенной в бесплатном хранилище, но не освобожденной. Чтобы обнаружить утечки, глобальные new операторы и delete переопределяются для подсчета выделения и освобождения памяти.

Компилятор поддерживает массив new и операторы-члены delete в объявлении класса. Пример:

Источник

BestProg

Содержание

Поиск на других ресурсах:

В Java для работы с объектами используется единый синтаксис. Объект класса объявляется с помощью ссылки (reference).
Общая форма объявления объекта класса без выделения памяти для него имеет следующий вид:

Если не выделить память для ссылки и обратиться к нему как к объекту класса, то возникнет ошибка.

Существует и другая общая форма объявления объекта класса. В этом случае память выделяется при его объявлении:

Выделение памяти для ссылки на объект класса еще называется «присоединение» объекта к ссылке.

2. Примеры создания объектов разных классов
3. Какие существуют области хранения данных в программах на Java?

В Java для хранения данных (объектов) существует 5 разных хранилищ:

4. В какой области памяти сохраняются объекты и ссылки на объекты?

Объекты сохраняются в «куче» (heap). Ссылки на объекты сохраняются в стеке.

5. Как в Java создаются и сохраняются массивы объектов?

В отличие от C/C++ массив в Java обязательно инициализируется. Доступ за пределами массива невозможен.
Чтобы создать массив объектов нужно использовать запись наподобие:

Это можно сделать другим способом, сразу при объявлении массива:

Память выделяется только для массива ссылок. Для объектов память еще не выделена. Чтобы выделить память для любого объекта нужно использовать приблизительно следующий код:

6. Пример объявления и инициализации массива объектов

Источник

new оператор (C++)

Пытается выделить и инициализировать объект или массив объектов указанного или типа заполнителя и возвращает подходящим образом типизированный указатель на объект (или на исходный объект массива).

Синтаксис

new-expression :
:: :: new new-placement new new-type-id new-initializer new-placement
:: :: new new-placement new ( type-id ) new-initializer new-placement

new-placement :
( expression-list )

new-type-id :
type-specifier-seq new-declarator type-specifier-seq

new-declarator :
ptr-operator new-declarator ptr-operator
noptr-new-declarator

noptr-new-declarator :
[ expression ] attribute-specifier-seq [
noptr-new-declarator [ constant-expression ] attribute-specifier-seq noptr-new-declarator

new-initializer :
( expression-list ( )
braced-init-list

Комментарии

В случае неудачи new возвращает ноль или вызывает исключение. Дополнительные сведения см. в разделе delete операторы и. Это поведение по умолчанию можно изменить, написав настраиваемую подпрограммы обработки исключений и вызвав _set_new_handler функцию библиотеки времени выполнения с именем функции в качестве аргумента.

Сведения о том, как создать объект в управляемой куче в C++/CLI и C++/CX, см. в разделе gcnew.

Если new используется для выделения памяти для объекта класса C++, конструктор объекта вызывается после выделения памяти.

Используйте delete оператор, чтобы освободить память, выделенную new оператором. Оператор используется delete[] для удаления массива, выделенного new оператором.

В следующем примере выделяется и затем освобождается двумерный массив символов размером dim на 10. При выделении многомерного массива все измерения, за исключением первого, должны быть константными выражениями, результатом вычисления которых являются положительные значения. Крайнее левое измерение массива может быть любым выражением, результатом вычисления которого является положительное значение. При выделении массива с помощью new оператора первое измерение может равняться нулю; new оператор возвращает уникальный указатель.

Объект type-id не может const содержать volatile объявления,, объявления классов и перечисления. Следующее выражение имеет неправильный формат:

new Оператор не выделяет ссылочные типы, так как они не являются объектами.

new Оператор нельзя использовать для выделения функции, но его можно использовать для выделения указателей на функции. В следующем примере выделяется и затем освобождается массив из семи указателей на функции, которые возвращают целые числа.

Если вы используете оператор new без каких бы то ни было дополнительных аргументов и компилируете с /GX /EHa /EHs параметром, или, компилятор создает код для вызова оператора, delete Если конструктор создает исключение.

В следующем списке описаны элементы грамматики new :

type-id
Указывает тип для выделения; Это может быть либо встроенный, либо определяемый пользователем тип. Если спецификация типа является сложной, она может быть окружена круглыми скобками, чтобы принудительно реализовать порядок привязки. Тип может быть заполнителем ( auto ), тип которого определяется компилятором.

new-initializer
Предоставляет значение для инициализированного объекта. Инициализаторы не могут быть указаны для массивов. new Оператор создает массивы объектов, только если у класса есть конструктор по умолчанию.

Пример: выделение и освобождение массива символов

Пример: new оператор

Если используется форма размещения new оператора (форма с дополнительными аргументами, чем размер), компилятор не поддерживает форму размещения delete оператора, если конструктор создает исключение. Пример:

Инициализация объектов, выделенных с помощью new

Необязательное new-initializer поле включено в грамматику для new оператора. Это поле позволяет инициализировать новые объекты с помощью пользовательских конструкторов. Дополнительные сведения о том, как выполняется инициализация, см. в разделе инициализаторы. В следующем примере показано, как использовать выражение инициализации с new оператором:

Если объект имеет тип класса и этот класс имеет конструкторы (как в предыдущем примере), объект может инициализироваться new оператором только в том случае, если выполняется одно из следующих условий:

Аргументы, указанные в инициализаторе, соответствуют аргументам конструктора.

Класс имеет конструктор по умолчанию (конструктор, который можно вызвать без аргументов).

Явная инициализация каждого элемента не может быть выполнена при выделении массивов с помощью new оператора; вызывается только конструктор по умолчанию, если он имеется. Дополнительные сведения см. в разделе аргументы по умолчанию.

Если выделение памяти завершается ошибкой ( operator new возвращает значение 0), инициализация не выполняется. Такое поведение защищает от попыток инициализировать несуществующие данные.

Как и при вызовах функций, порядок вычисления инициализированных выражений не определен. Кроме того, не следует полагаться на эти выражения полностью, прежде чем выделять память. Если выделение памяти завершается ошибкой и new оператор возвращает ноль, некоторые выражения в инициализаторе не могут быть вычислены полностью.

Время существования объектов, выделенных с помощью new

Объекты, выделенные с помощью new оператора, не уничтожаются при выходе из области видимости, в которой они определены. Поскольку new оператор возвращает указатель на объекты, которые он выделяет, программа должна определить указатель с подходящей областью для доступа к этим объектам и удаления этих объектов. Пример:

После того как указатель AnotherArray в этом примере вышел за пределы области видимости, объект невозможно удалить.

Как работает new

new-expression (Выражение, содержащее new оператор) выполняет три вещи:

Находит и резервирует хранилище для объекта или объектов, которым нужно выделить память. После завершения этого этапа выделяется правильный объем хранилища, но еще не объект.

Инициализирует объекты. После завершения инициализации имеется достаточно информации, чтобы выделенная память являлась объектом.

Исходная цель new-placement поля — разрешить выделение аппаратно зависимых объектов по указанным пользователем адресам.

Хотя в предыдущем примере показан только один аргумент в new-placement поле, не существует ограничений на количество дополнительных аргументов, которые могут быть переданы operator new таким образом.

Оператор разрешения области действия ( :: ) принудительно использует глобальный new оператор.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *