Операторы new
и delete
C++ поддерживает динамическое выделение и размещение объектов с помощью new
операторов.delete
Эти операторы выделяют память для объектов из пула, называемого бесплатным хранилищем (также известное как куча). Оператор new
вызывает специальную функцию operator new
, а delete
оператор вызывает специальную функцию operator delete
.
Список файлов библиотеки в библиотеке среды выполнения C и стандартной библиотеке C++ см. в разделе "Функции библиотеки CRT".
Оператор new
Компилятор преобразует оператор, такой как этот, в вызов функции operator new
:
char *pch = new char[BUFFER_SIZE];
Если запрос равен нулю байтов хранилища, operator new
возвращает указатель на отдельный объект. То есть повторяющиеся вызовы для operator new
возврата разных указателей.
Если для запроса на выделение недостаточно памяти, operator new
создается std::bad_alloc
исключение. Кроме того, он возвращаетсяnullptr
, если вы использовали форму new(std::nothrow)
размещения или если вы связали в неисключаемой поддержкеoperator new
. Дополнительные сведения см. в разделе "Поведение сбоя выделения".
Два область для operator new
функций описаны в следующей таблице.
Область для operator new
функций
Оператор | Область |
---|---|
::operator new |
Глобальный |
имя класса::operator new |
Класс |
Первый аргумент operator new
должен быть типом size_t
, а возвращаемый тип всегда void*
.
Глобальная operator new
функция вызывается, когда new
оператор используется для выделения объектов встроенных типов, объектов типа класса, которые не содержат определяемых operator new
пользователем функций и массивов любого типа. new
Когда оператор используется для выделения объектов типа класса, в котором определен объектoperator new
, вызывается этот классoperator new
.
Функция, определенная operator new
для класса, представляет собой статическую функцию-член (которая не может быть виртуальной), которая скрывает глобальную operator new
функцию для объектов этого типа класса. Рассмотрим случай, когда new
используется для выделения и задания памяти заданному значению:
#include <malloc.h>
#include <memory.h>
class Blanks
{
public:
Blanks(){}
void *operator new( size_t stAllocateBlock, char chInit );
};
void *Blanks::operator new( size_t stAllocateBlock, char chInit )
{
void *pvTemp = malloc( stAllocateBlock );
if( pvTemp != 0 )
memset( pvTemp, chInit, stAllocateBlock );
return pvTemp;
}
// For discrete objects of type Blanks, the global operator new function
// is hidden. Therefore, the following code allocates an object of type
// Blanks and initializes it to 0xa5
int main()
{
Blanks *a5 = new(0xa5) Blanks;
return a5 != 0;
}
Аргумент, предоставленный в скобках, new
передается Blanks::operator new
в качестве аргумента chInit
. Однако глобальная operator new
функция скрыта, что приводит к возникновению ошибки, например следующего кода:
Blanks *SomeBlanks = new Blanks;
Компилятор поддерживает массив new
элементов и delete
операторы в объявлении класса. Например:
class MyClass
{
public:
void * operator new[] (size_t)
{
return 0;
}
void operator delete[] (void*)
{
}
};
int main()
{
MyClass *pMyClass = new MyClass[5];
delete [] pMyClass;
}
Поведение сбоя выделения
Функция new
в стандартной библиотеке C++ поддерживает поведение, указанное в стандарте C++ с C++98. Если для запроса на выделение недостаточно памяти, operator new
создается std::bad_alloc
исключение.
Старый код C++ вернул указатель null для неудавшихся выделений. Если у вас есть код, который ожидает неисключаемую версию new
, свяжите программу с nothrownew.obj
. Файл nothrownew.obj
заменяет глобальную operator new
версию, которая возвращается nullptr
при сбое выделения. operator new
больше не бросает std::bad_alloc
. Дополнительные сведения о nothrownew.obj
файлах параметров компоновщика см. в разделе "Параметры ссылки".
Нельзя смешивать код, который проверка для исключений из глобального operator new
кода, который проверка для указателей NULL в одном приложении. Однако вы по-прежнему можете создавать локальные operator new
классы, которые ведут себя по-разному. Эта возможность означает, что компилятор должен выполнять оборонительные действия по умолчанию и включать проверка для возвращаемых указателей NULL в new
вызовах. Дополнительные сведения об оптимизации этих проверка компилятора см. в статье /Zc:throwingnew
.
Обработка нехватки памяти
Способ тестирования для неудавшихся выделений из new
выражения зависит от того, используется ли стандартный механизм исключений nullptr
или используется возврат. Стандартный C++ ожидает, что std::bad_alloc
выделяющий объект или класс, производный от std::bad_alloc
. Вы можете обработать такое исключение, как показано в этом примере:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
try {
int *pI = new int[BIG_NUMBER];
}
catch (bad_alloc& ex) {
cout << "Caught bad_alloc: " << ex.what() << endl;
return -1;
}
}
При использовании формы new
можно проверить сбой nothrow
выделения, как показано в этом примере:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new(nothrow) int[BIG_NUMBER];
if ( pI == nullptr ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
Если вы использовали nothrownew.obj
файл для замены глобального operator new
файла, можно протестировать выделение памяти сбоем, как показано ниже.
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new int[BIG_NUMBER];
if ( !pI ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
Вы можете предоставить обработчик для неудачных запросов на выделение памяти. Можно написать настраиваемую процедуру восстановления для обработки такого сбоя. Например, он может освободить зарезервированную память, а затем разрешить повторное выполнение выделения. Дополнительные сведения см. в разделе _set_new_handler
.
Оператор delete
Память, которая динамически выделяется с помощью new
оператора, можно освободить с помощью delete
оператора. Оператор удаления вызывает operator delete
функцию, которая освобождает память обратно в доступный пул. delete
Использование оператора также приводит к вызову деструктора класса (если он существует).
Существуют глобальные функции и функции область классаoperator delete
. Для данного класса можно определить только одну operator delete
функцию. Если она определена, она скрывает глобальную operator delete
функцию. Глобальная operator delete
функция всегда вызывается для массивов любого типа.
Глобальная operator delete
функция. Для глобальных operator delete
и членных operator delete
функций существуют две формы:
void operator delete( void * );
void operator delete( void *, size_t );
Для данного класса может присутствовать только одна из предыдущих двух форм. Первая форма принимает один аргумент типа void *
, который содержит указатель на объект для освобождения. Вторая форма, размер сделки, принимает два аргумента: первый — указатель на блок памяти для освобождения, а второй — число байтов для освобождения. Возвращаемый тип обеих форм — (void
operator delete
не может возвращать значение).
Цель второй формы — ускорить поиск правильной категории размера объекта для удаления. Эта информация часто не хранится рядом с самим выделением и, скорее всего, не качается. Вторая форма полезна, если operator delete
функция из базового класса используется для удаления объекта производного класса.
Функция operator delete
является статической, поэтому она не может быть виртуальной. Функция operator delete
подчиняется управлению доступом, как описано в разделе "Член-контроль доступа".
В следующем примере показаны определяемые operator new
пользователем функции и operator delete
функции, предназначенные для выделения журналов и размещения памяти:
#include <iostream>
using namespace std;
int fLogMemory = 0; // Perform logging (0=no; nonzero=yes)?
int cBlocksAllocated = 0; // Count of blocks allocated.
// User-defined operator new.
void *operator new( size_t stAllocateBlock ) {
static int fInOpNew = 0; // Guard flag.
if ( fLogMemory && !fInOpNew ) {
fInOpNew = 1;
clog << "Memory block " << ++cBlocksAllocated
<< " allocated for " << stAllocateBlock
<< " bytes\n";
fInOpNew = 0;
}
return malloc( stAllocateBlock );
}
// User-defined operator delete.
void operator delete( void *pvMem ) {
static int fInOpDelete = 0; // Guard flag.
if ( fLogMemory && !fInOpDelete ) {
fInOpDelete = 1;
clog << "Memory block " << cBlocksAllocated--
<< " deallocated\n";
fInOpDelete = 0;
}
free( pvMem );
}
int main( int argc, char *argv[] ) {
fLogMemory = 1; // Turn logging on
if( argc > 1 )
for( int i = 0; i < atoi( argv[1] ); ++i ) {
char *pMem = new char[10];
delete[] pMem;
}
fLogMemory = 0; // Turn logging off.
return cBlocksAllocated;
}
Предыдущий код можно использовать для обнаружения утечки памяти, то есть памяти, выделенной в свободном хранилище, но никогда не освобождаемой. Чтобы обнаружить утечки, глобальные new
и delete
операторы переопределяются для подсчета распределения и распределения памяти.
Компилятор поддерживает массив new
элементов и delete
операторы в объявлении класса. Например:
// spec1_the_operator_delete_function2.cpp
// compile with: /c
class X {
public:
void * operator new[] (size_t) {
return 0;
}
void operator delete[] (void*) {}
};
void f() {
X *pX = new X[5];
delete [] pX;
}
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по