Создать и удалить (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]

Смотрите также

Рекомендации

  1. ^ а б Савич, Уолтер (2013). Абсолютный C ++. Пирсон. С. 420–445. ISBN  0132846810.
  2. ^ "Документация IBM с описанием оператора C ++ new". Архивировано из оригинал на 2013-01-03. Получено 2013-11-06.
  3. ^ «Новая документация оператора Microsoft Visual Studio». Получено 2013-11-06.
  4. ^ а б Страуструп, Бьярне (1993). История C ++: 1979–1991 (PDF). Proc. ACM История языков программирования, конф.
  5. ^ Мейерс, Скотт (1998). Эффективный C ++. Эддисон-Уэсли. п.21.
  6. ^ Александреску, Андрей (2001). Современный дизайн на C ++: применение общих шаблонов программирования и проектирования. Эддисон-Уэсли. п.68.
  7. ^ Сикорд, Роберт С. (2013). Безопасное кодирование на C и C ++. Эддисон-Уэсли. Раздел 4.4, Распространенные ошибки управления памятью C ++.