operator new, operator new[]
Определено в заголовке <new> | ||||||
|---|---|---|---|---|---|---|
функции замещающей аллокации
| ||||||
void* operator new ( std::size_t count ); | (1) | |||||
void* operator new[]( std::size_t count ); | (2) | |||||
void* operator new ( std::size_t count, std::align_val_t al ); | (3) | (с C++17) | ||||
void* operator new[]( std::size_t count, std::align_val_t al ); | (4) | (с C++17) | ||||
функции замещающей безбросковой аллокации
| ||||||
void* operator new ( std::size_t count, const std::nothrow_t& tag ); | (5) | |||||
void* operator new[]( std::size_t count, const std::nothrow_t& tag ); | (6) | |||||
void* operator new ( std::size_t count,
std::align_val_t al, const std::nothrow_t& ); | (7) | (с C++17) | ||||
void* operator new[]( std::size_t count,
std::align_val_t al, const std::nothrow_t& ); | (8) | (с C++17) | ||||
функции замещающей аллокации без выделения памяти
| ||||||
void* operator new ( std::size_t count, void* ptr ); | (9) | |||||
void* operator new[]( std::size_t count, void* ptr ); | (10) | |||||
| функции замещающей аллокации, заданные пользователем | ||||||
void* operator new ( std::size_t count, user-defined-args... ); | (11) | |||||
void* operator new[]( std::size_t count, user-defined-args... ); | (12) | |||||
void* operator new ( std::size_t count,
std::align_val_t al, user-defined-args... ); | (13) | (с C++17) | ||||
void* operator new[]( std::size_t count,
std::align_val_t al, user-defined-args... ); | (14) | (с C++17) | ||||
| функции аллокации, специфичные для класса | ||||||
void* T::operator new ( std::size_t count ); | (15) | |||||
void* T::operator new[]( std::size_t count ); | (16) | |||||
void* T::operator new ( std::size_t count, std::align_val_t al ); | (17) | (с C++17) | ||||
void* T::operator new[]( std::size_t count, std::align_val_t al ); | (18) | (с C++17) | ||||
| функции размещенной аллокации, специфичные для класса | ||||||
void* T::operator new ( std::size_t count, user-defined-args... ); | (19) | |||||
void* T::operator new[]( std::size_t count, user-defined-args... ); | (20) | |||||
void* T::operator new ( std::size_t count,
std::align_val_t al, user-defined-args... ); | (21) | (с C++17) | ||||
void* T::operator new[]( std::size_t count,
std::align_val_t al, user-defined-args... ); | (22) | (с C++17) |
Попытки выделить запрошенное количество байтов, и запрос выделения памяти может завершиться неудачей (даже если запрошенное количество байтов равно нулю). Эти функции выделения вызываются выражениями new для выделения памяти, в которой затем будет инициализирован новый объект. Они также могут быть вызваны с использованием обычной синтаксической конструкции вызова функций.
count байт из свободного пространства. В случае неудачи, реализация стандартной библиотеки вызывает указатель функции, возвращённый std::get_new_handler, и повторяет попытки выделения, пока обработчик new не вернёт значение или не станет нулевым указателем, в котором случае бросается исключение std::bad_alloc. Эта функция должна возвращать указатель, соответствующий выравниванию к объекту запрошенного размера.__STDCPP_DEFAULT_NEW_ALIGNMENT__.__STDCPP_DEFAULT_NEW_ALIGNMENT__.__STDCPP_DEFAULT_NEW_ALIGNMENT__. Реализация стандартной библиотеки вызывает версию (3) и возвращает нулевой указатель при ошибке вместо распространения исключения.__STDCPP_DEFAULT_NEW_ALIGNMENT__. Реализация стандартной библиотеки вызывает версию (4) и возвращает нулевой указатель при ошибке вместо распространения исключения.ptr без изменений. Поведение не определено, если эта функция вызывается через выражение placement new и ptr — нулевой указатель.ptr без изменений. Поведение не определено, если эта функция вызывается через выражение placement new и ptr — нулевой указатель.__STDCPP_DEFAULT_NEW_ALIGNMENT__. Если определена версия класса (15) или (17), она вызывается вместо неё. Если не указана ни класс-специфичная, ни глобальная версия с учётом выравнивания, то используется версия без учёта выравнивания (11).__STDCPP_DEFAULT_NEW_ALIGNMENT__. Если определена версия класса (16) или (18), она вызывается вместо неё. Если не указана ни класс-специфичная, ни глобальная версия с учётом выравнивания, то используется версия без учёта выравнивания (12).__STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не указан, но указана версия без учёта выравнивания (15), вызывается версия без учёта выравнивания.__STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не предоставлен, но перегрузка член-функции без учета выравнивания (16) — есть, используется перегрузка члена-функции без учета выравнивания.__STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не предоставлен, но перегрузка член-функции без учета выравнивания (19) — есть, используется перегрузка члена-функции без учета выравнивания.__STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не предоставлен, но перегрузка член-функции без учета выравнивания (20) — есть, используется перегрузка члена-функции без учета выравнивания.Параметры
| count | - | количество байтов для выделения |
| ptr | - | указатель на область памяти для инициализации объекта |
| tag | - | метка разбора, используемая для выбора перегрузок без исключений |
| al | - | выравнивание для использования. Поведение неопределено, если это не допустимое значение выравнивания |
Возвращаемое значение
p0 , который указывает на подходяще выровненную память размером не менее size и отличается от любого ранее возвращенного значения p1, если это значение p1 не было затем передано в заменяемую функцию освобождения памяти; если выделение не удалось, не возвращает (исключение выбрасывается, см. ниже).ptr
Исключение
std::bad_alloc при неудачном выделении памяти.Глобальные замены
Версии (1-4) неявно объявляются в каждом файле трансляции, даже если заголовок <new> не включен. Версии (1-8) заменяемые: пользовательская функция без указания класса с той же сигнатурой, определённая где-либо в программе, в любом исходном файле, заменяет стандартную версию. Её объявление не обязательно видно.
Программа некорректна (без диагностики), если более чем одна замена предоставлена в программе для любой из заменяемых функций выделения или если замена объявлена с inline спецификатором. Программа некорректна, если замена определена в пространстве имён, отличном от глобального пространства имён, или если она определена как статическая функция без указания класса на глобальном уровне.
Реализации стандартной библиотеки для версий без исключений (5-8) напрямую вызывают соответствующие версии с исключениями (1-4). Реализация стандартной библиотеки для версий выделения массивов с исключениями (2,4) напрямую вызывает соответствующие версии выделения одиночного объекта (1,3). Таким образом, замена функций выделения одиночного объекта с исключениями достаточно для обработки всех выделений.
| В реализациях без среды выполнения поведение по умолчанию для (1-8) определяется реализацией. Реализации без среды выполнения рекомендуются, что если какая-либо из этих версий по умолчанию соответствует требованиям реализаций со средой выполнения, они все должны. | (с C++26) |
Глобальная operator замена new/delete:
#include <cstdio>
#include <cstdlib>
#include <new>
// no inline, required by [replacement.functions]/3
void* operator new(std::size_t sz)
{
std::printf("1) new(size_t), size = %zu\n", sz);
if (sz == 0)
++sz; // avoid std::malloc(0) which may return nullptr on success
if (void *ptr = std::malloc(sz))
return ptr;
throw std::bad_alloc{}; // required by [new.delete.single]/3
}
// no inline, required by [replacement.functions]/3
void* operator new[](std::size_t sz)
{
std::printf("2) new[](size_t), size = %zu\n", sz);
if (sz == 0)
++sz; // avoid std::malloc(0) which may return nullptr on success
if (void *ptr = std::malloc(sz))
return ptr;
throw std::bad_alloc{}; // required by [new.delete.single]/3
}
void operator delete(void* ptr) noexcept
{
std::puts("3) delete(void*)");
std::free(ptr);
}
void operator delete(void* ptr, std::size_t size) noexcept
{
std::printf("4) delete(void*, size_t), size = %zu\n", size);
std::free(ptr);
}
void operator delete[](void* ptr) noexcept
{
std::puts("5) delete[](void* ptr)");
std::free(ptr);
}
void operator delete[](void* ptr, std::size_t size) noexcept
{
std::printf("6) delete[](void*, size_t), size = %zu\n", size);
std::free(ptr);
}
int main()
{
int* p1 = new int;
delete p1;
int* p2 = new int[10]; // guaranteed to call the replacement in C++11
delete[] p2;
}Возможный вывод:
// Compiled with GCC-5 in C++17 mode to obtain the following: 1) op new(size_t), size = 4 4) op delete(void*, size_t), size = 4 2) op new[](size_t), size = 40 5) op delete[](void* ptr)
Перегрузки operator new и operator new[] с дополнительными пользовательскими параметрами («формы размещения», версии (11-14)) могут быть объявлены на глобальном уровне как обычно и вызываются соответствующими формами размещения выражений new.
Невыделяющие формы размещения operator new (9,10) в стандартной библиотеке не могут быть заменены и могут быть настроены только если выражение placement new не использовало синтаксис ::new, предоставив классоспецифическую форму размещения new (19,20) с соответствующей сигнатурой: void* T::operator new(std::size_t, void*) или void* T::operator new[](std::size_t, void*).
| Форма размещения void* operator new(std::size_t, std::size_t) не допускается, так как соответствующая сигнатура функции освобождения памяти, void operator delete(void*, std::size_t), является обычной (не размещенной) функцией освобождения памяти. | (с C++14) |
Класс-специфические перегрузки
Функции выделения как одиночных объектов, так и массивов могут быть определены как публичные статические члены класса (версии (15-18)). При определении эти функции выделения вызываются выражениями new для выделения памяти для одиночных объектов и массивов этого класса, если выражение new не использовало форму ::new, которая обходит поиск в области видимости класса. Ключевое слово static для этих функций необязательно: используется оно или нет, функция выделения является статическим членом класса.
Выражение new ищет соответствующую функцию выделения сначала в области видимости класса, а затем в глобальной области видимости. Обратите внимание, что согласно правилам поиска имён, любая функция выделения, объявленная в области видимости класса, скрывает все глобальные функции выделения для выражений new, которые пытаются выделить объекты этого класса.
| При выделении объектов и массивов объектов, выравнивание которых превышает | (с C++17) |
| При выделении объектов и массивов объектов, выравнивание которых не превышает | (с C++20) |
#include <cstddef>
#include <iostream>
// class-specific allocation functions
struct X
{
static void* operator new(std::size_t count)
{
std::cout << "custom new for size " << count << '\n';
return ::operator new(count);
}
static void* operator new[](std::size_t count)
{
std::cout << "custom new[] for size " << count << '\n';
return ::operator new[](count);
}
};
int main()
{
X* p1 = new X;
delete p1;
X* p2 = new X[10];
delete[] p2;
}Возможный вывод:
custom new for size 1 custom new[] for size 10
Перегрузки operator new и operator new[] с дополнительными пользовательскими параметрами («формы размещения») также могут быть определены как члены класса (19-22). Когда выражение placement new с соответствующей сигнатурой ищет соответствующую функцию выделения для вызова, оно начинает в области видимости класса, прежде чем проверять глобальную область видимости, и если предоставлена класс-специфическая форма размещения new, она вызывается.
| При выделении объектов и массивов объектов, выравнивание которых превышает | (с C++17) |
| При выделении объектов и массивов объектов, выравнивание которых не превышает | (с C++20) |
#include <cstddef>
#include <iostream>
#include <stdexcept>
struct X
{
X() { throw std::runtime_error(""); }
// custom placement new
static void* operator new(std::size_t count, bool b)
{
std::cout << "custom placement new called, b = " << b << '\n';
return ::operator new(count);
}
// custom placement delete
static void operator delete(void* ptr, bool b)
{
std::cout << "custom placement delete called, b = " << b << '\n';
::operator delete(ptr);
}
};
int main()
{
try
{
[[maybe_unused]] X* p1 = new (true) X;
}
catch (const std::exception&)
{}
}Вывод:
custom placement new called, b = 1 custom placement delete called, b = 1
Если operator new на уровне класса является шаблонной функцией, она должна иметь тип возвращаемого значения void*, первый аргумент std::size_t, и она должна иметь два или более параметров. Другими словами, только размещаемые формы могут быть шаблонами.
Примечания
Несмотря на то, что невыделяющая размещаемая операция new (9,10) не может быть заменена, функция с такой же сигнатурой может быть определена на уровне класса, как описано выше. Кроме того, разрешены глобальные перегрузки, похожие на размещаемую операцию new, но принимающие тип указателя, отличный от void, в качестве второго аргумента. Поэтому код, который хочет гарантировать, что вызывается именно размещаемая операция new (например, std::allocator::construct), должен использовать ::new и также привести указатель к типу void*.
Если поведение функции освобождения не удовлетворяет стандартным ограничениям, такое поведение неопределенно.
| Следующие функции должны быть потокобезопасными:
Вызовы этих функций, которые выделяют или освобождают определенный блок памяти, происходят в едином общем порядке, и каждый вызов освобождения предшествует следующему выделению (если оно есть) в этом порядке. | (с C++11) |
Не определено, производят ли библиотечные версии operator new какие-либо вызовы std::malloc или std::aligned_alloc(с C++17).
Для загрузки большого файла предпочтительнее использовать отображение файла с помощью функций операционной системы, например, mmap на POSIX или CreateFileMapping(A/W) вместе с MapViewOfFile на Windows, а не выделять буфер для чтения файла.
| Макрокоманда проверки наличия функции | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_lib_freestanding_operator_new | 202306L | (C++26) | Поддержка свободных операторов new[1] |
| 0 | (C++26) | Отсутствует поддержка свободных операторов |
- Формально, эта макрокоманда расширяется до
202306Lесли все стандартные реализации замещаемых глобальных функций выделения удовлетворяют требованиям хостированной реализации.
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение, как опубликовано | Корректное поведение |
|---|---|---|---|
| CWG 521 | C++98 | любой класс, унаследованный от std::bad_alloc, мог быть брошен,даже если базовый класс std::bad_alloc был неоднозначным или недоступным | выброшенное исключение должно соответствовать обработчику типа std::bad_alloc |
| LWG 9 | C++98 | несколько вызовов для выделения нулевых байтов могли привести к одному и тому же указателю | разрешено только если все такие ранее полученные указатели были переданы функциям освобождения |
| LWG 206 | C++98 | замена замещаемых функций выделения не влияла на поведение по умолчанию соответствующих замещаемых функций выделения без исключений | поведение по умолчанию изменяется соответствующим образом |
| LWG 404 | C++98 | замены замещаемых функций выделения могли быть объявлены inline | запрещено, не требуется диагностика |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2023):
- 17.7 Динамическое управление памятью [support.dynamic]
- Стандарт C++20 (ISO/IEC 14882:2020):
- 17.6 Динамическое управление памятью [support.dynamic]
- Стандарт C++17 (ISO/IEC 14882:2017):
- 21.6 Динамическое управление памятью [support.dynamic]
- Стандарт C++14 (ISO/IEC 14882:2014):
- 18.6 Динамическое управление памятью [support.dynamic]
- Стандарт C++11 (ISO/IEC 14882:2011):
- 18.6 Динамическое управление памятью [support.dynamic]
См. также
| функции освобождения (функция) |
|
|
(C++11) | получает текущий обработчик new (функция) |
| регистрирует обработчик new (функция) |
|
|
(устарело в C++17)(удалено в C++20) | получает неинициализированный блок памяти (шаблон функции) |
| выделяет память (функция) |
|
|
(C++17) | выделяет выровненную память (функция) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/memory/new/operator_new