Создать и удалить (C ++) - New and delete (C++)
в C ++ язык программирования, новый и Удалить пара языковых конструкций, которые выполняют распределение динамической памяти, строительство объекта и разрушение объекта.[1]
Обзор
За исключением формы, называемой "размещение новое", то новый оператор обозначает запрос на выделение памяти для процесса куча. Если доступно достаточно памяти, новый инициализирует память, при необходимости вызывая конструкторы объектов, и возвращает адрес вновь выделенной и инициализированной памяти.[2][3] А новый Запрос в простейшем виде выглядит следующим образом:
п = новый Т;
куда п ранее объявленный указатель типа Т (или какой-то другой тип, к которому Т может быть назначен указатель, например суперкласс из Т). В конструктор по умолчанию за Т, если таковые имеются, вызывается для построения Т экземпляр в выделенном буфере памяти.
Если в бесплатном хранилище недостаточно памяти для объекта типа Т, то новый запрос указывает на сбой, бросая исключение типа std :: bad_alloc. Это избавляет от необходимости явно проверять результат выделения.
Аналог освобождения новый является Удалить, который сначала вызывает деструктор (если есть) для своего аргумента, а затем возвращает память, выделенную новый обратно в бесплатный магазин. Каждый звонок новый должен сопровождаться вызовом Удалить; невыполнение этого причины утечки памяти.[1]
новый Синтаксис имеет несколько вариантов, которые позволяют более точно контролировать выделение памяти и создание объектов. Синтаксис, подобный вызову функции, используется для вызова конструктора, отличного от конструктора по умолчанию, и передачи ему аргументов, например,
п = новый Т(аргумент);
вызывает единственный аргумент Т конструктор вместо конструктора по умолчанию при инициализации вновь выделенного буфера.
Другой вариант выделяет и инициализирует массивы объектов, а не отдельных объектов:
п = новый Т [N];
Это запрашивает буфер памяти из свободного хранилища, который достаточно велик для хранения непрерывного массива N объекты типа Т, непрерывно и вызывает конструктор по умолчанию для каждого элемента массива.
Память, выделенная новый[] должен быть освобожден от Удалить[] оператор, а не Удалить. Использование неподходящей формы приводит к неопределенное поведение. Компиляторы C ++ не обязаны генерировать диагностическое сообщение об использовании неправильной формы.
В C ++ 11 стандарт определяет дополнительный синтаксис,
п = новый Т[N] {инициализатор1, ..., инициализаторN};
который инициализирует каждый п[я] к инициализаторя + 1.
Обработка ошибок
Если новый не может найти достаточно памяти для обслуживания запроса на выделение памяти, он может сообщить об ошибке тремя разными способами. Во-первых, Стандарт ISO C ++ позволяет программам регистрировать пользовательскую функцию, называемую new_handler с C ++ время выполнения; если это так, то эта функция вызывается всякий раз, когда новый обнаруживает ошибку. В new_handler может попытаться освободить больше памяти или завершить программу, если не может.
Если нет new_handler установлен, новый вместо этого бросает исключение типа std :: bad_alloc. Таким образом, программе не нужно проверять значение возвращаемого указателя, как это принято в C; если исключение не было создано, выделение выполнено успешно.
Третий способ обработки ошибок - вариантная форма новый (std :: nothrow), который указывает, что исключение не должно создаваться; вместо этого нулевой указатель возвращается, чтобы сигнализировать об ошибке распределения.
Перегрузка
В новый оператор может быть перегружен чтобы определенные типы (классы) использовали собственные алгоритмы выделения памяти для своих экземпляров. Например, ниже представлен вариант одноэлементный образец где первый новый синглтон call выделяет экземпляр, и все последующие вызовы возвращают этот же экземпляр:
1 #включают <cstdlib> 2 #включают <cstddef> 3 4 учебный класс Синглтон; 5 6 пространство имен { 7 пустота* g_instance = nullptr; 8 стандартное::size_t g_refcount = 0; 9 } // пространство имен10 11 учебный класс Синглтон {12 общественный:13 статический пустота* оператор новый(стандартное::size_t nbytes) {14 если (g_instance == nullptr) {15 g_instance = стандартное::маллок(nbytes);16 }17 g_refcount++;18 возвращаться g_instance;19 }20 21 статический пустота оператор Удалить(пустота* п) {22 если (--g_refcount == 0) {23 стандартное::свободный(g_instance);24 g_instance = nullptr;25 }26 }27 };
Эта функция была доступна с самого начала в истории C ++, хотя конкретный механизм перегрузки изменился. Он был добавлен в язык, потому что объектно-ориентированный Программы на C ++ имели тенденцию выделять множество мелких объектов с помощью новый, который внутренне использовал распределитель C (см. § Отношение к malloc и free ); это, однако, было оптимизировано для меньшего и большего выделения памяти, выполняемого типичными программами C. Страуструп сообщил, что в ранних приложениях функция C маллок был «наиболее частым узким местом в производительности реальных систем», когда программы тратили до 50% своего времени на эту функцию.[4]
пустота *оператор новый(size_t размер)
Конструкция языка C ++, которая выделяет только память, называется пустота *оператор новый(size_t размер)
. Он используется новый в фазе распределения. Его можно переопределить для каждого класса или глобально, чтобы определить конкретный распределитель памяти.
Отношение к malloc и free
Поскольку стандартный C ++ включает Стандартная библиотека C, то Распределение динамической памяти C распорядки маллок, каллок, перераспределить и свободный также доступны для программистов на C ++. В большинстве случаев использование этих подпрограмм не рекомендуется, поскольку они не выполняют инициализацию и уничтожение объектов.[5] новый и Удалить были фактически введены в первой версии C ++ (тогда называемой "C с классами "), чтобы избежать необходимости инициализации объекта вручную.[4]
В отличие от процедур C, которые позволяют увеличивать или уменьшать выделенный массив с помощью перераспределить, невозможно изменить размер буфера памяти, выделенного новый[]. В Стандартная библиотека C ++ вместо этого предоставляет динамический массив (коллекция), которая может быть расширена или сокращена в std :: vector класс шаблона.
Стандарт C ++ не определяет никакой связи между новый/Удалить и процедуры выделения памяти C, но новый и Удалить обычно реализуются как оболочки вокруг маллок и свободный.[6] Смешивание двух семейств операций, например, свободный'ing новыйвыделенная память или Удалить'ing маллок'd памяти, вызывает неопределенное поведение и на практике может привести к различным катастрофическим результатам, таким как отказ от выпуска замки и поэтому тупик.[7]
Смотрите также
- Распределитель (C ++)
- Обработка исключений
- Пул памяти
- Указатель (компьютерное программирование)
- Приобретение ресурсов - это инициализация (RAII)
- Умные указатели
Рекомендации
- ^ а б Савич, Уолтер (2013). Абсолютный C ++. Пирсон. С. 420–445. ISBN 0132846810.
- ^ "Документация IBM с описанием оператора C ++ new". Архивировано из оригинал на 2013-01-03. Получено 2013-11-06.
- ^ «Новая документация оператора Microsoft Visual Studio». Получено 2013-11-06.
- ^ а б Страуструп, Бьярне (1993). История C ++: 1979–1991 (PDF). Proc. ACM История языков программирования, конф.
- ^ Мейерс, Скотт (1998). Эффективный C ++. Эддисон-Уэсли. п.21.
- ^ Александреску, Андрей (2001). Современный дизайн на C ++: применение общих шаблонов программирования и проектирования. Эддисон-Уэсли. п.68.
- ^ Сикорд, Роберт С. (2013). Безопасное кодирование на C и C ++. Эддисон-Уэсли. Раздел 4.4, Распространенные ошибки управления памятью C ++.