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) | (noexcept начиная с C++11) |
|
void
*
operator new
[
]
(
std::
size_t
count,
const
std::
nothrow_t
&
tag
)
;
|
(6) | (noexcept начиная с C++11) |
|
void
*
operator new
(
std::
size_t
count,
std::
align_val_t
al,
const std:: nothrow_t & tag ) noexcept ; |
(7) | (начиная с C++17) |
|
void
*
operator new
[
]
(
std::
size_t
count,
std::
align_val_t
al,
const std:: nothrow_t & tag ) noexcept ; |
(8) | (начиная с C++17) |
|
Неразмещающие функции размещения с размещением
|
||
|
void
*
operator new
(
std::
size_t
count,
void
*
ptr
)
;
|
(9) |
(noexcept начиная с C++11)
(constexpr начиная с C++26) |
|
void
*
operator new
[
]
(
std::
size_t
count,
void
*
ptr
)
;
|
(10) |
(noexcept начиная с C++11)
(constexpr начиная с C++26) |
|
Пользовательские функции размещающего выделения памяти
|
||
|
void
*
operator new
(
std::
size_t
count,
/* аргументы... */
)
;
|
(11) | |
|
void
*
operator new
[
]
(
std::
size_t
count,
/* аргументы... */
)
;
|
(12) | |
|
void
*
operator new
(
std::
size_t
count,
std:: align_val_t al, /* аргументы... */ ) ; |
(13) | (начиная с C++17) |
|
void
*
operator new
[
]
(
std::
size_t
count,
std:: align_val_t al, /* 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,
/* аргументы... */
)
;
|
(19) | |
|
void
*
T
::
operator
new
[
]
(
std::
size_t
count,
/* аргументы... */
)
;
|
(20) | |
|
void
*
T
::
operator
new
(
std::
size_t
count,
std:: align_val_t al, /* args... */ ) ; |
(21) | (начиная с C++17) |
|
void
*
T
::
operator
new
[
]
(
std::
size_t
count,
std:: align_val_t al, /* аргументы... */ ) ; |
(22) | (начиная с C++17) |
Пытается выделить запрошенное количество байт, и запрос на выделение может завершиться неудачей (даже если запрошенное количество байт равно нулю). Эти функции выделения вызываются new выражениями для выделения памяти, в которой затем будет инициализирован новый объект. Они также могут быть вызваны с использованием обычного синтаксиса вызова функции.
Перегрузки ( 1-4 ) неявно объявляются в каждой единице трансляции, даже если заголовочный файл <new> не включен.
См. new expression для критериев выбора перегрузки.
Содержание |
Параметры
| count | - | количество байт для выделения |
| ptr | - | указатель на область памяти для инициализации объекта |
| tag | - | тег устранения неоднозначности для выбора непорождающих исключения перегрузок |
| al | - | выравнивание для использования, недопустимое значение приводит к неопределенному поведению |
Возвращаемое значение
Исключения
Глобальные замены
Перегрузки ( 1-8 ) являются заменяемыми . Эффекты версий по умолчанию следующие:
- Если попытка успешна, возвращает указатель на выделенную память.
- В противном случае, если в данный момент не установлен new-handler , генерирует исключение std::bad_alloc .
-
В противном случае вызывает текущий установленный new-handler.
- Если new-handler возвращает управление, начинает новую попытку выделения.
- В противном случае завершает текущий вызов.
- Если вызов завершается нормально, возвращает результат этого вызова.
- В противном случае возвращает нулевой указатель.
|
В автономных реализациях , определяется реализацией, удовлетворяют ли стандартные версии ( 1-8 ) требованиям к поведению, указанным выше. Рекомендуется, чтобы в автономных реализациях, если какие-либо из этих стандартных версий соответствуют требованиям hosted-реализации, все они должны соответствовать. |
(since 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[]
с дополнительными пользовательскими параметрами ("placement forms", версии
(
11-14
)
) могут быть объявлены в глобальной области видимости как обычно и вызываются соответствующими
placement forms
выражений
new
.
Нераспределяющие формы размещающего
operator new
(
9,10
)
из стандартной библиотеки не могут быть заменены и могут быть настроены только если размещающее выражение
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 , которые пытаются выделить объекты этого класса.
|
При выделении памяти для объектов и массивов объектов, выравнивание которых превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки выполняется дважды: сначала для сигнатур функций с учетом выравнивания, затем для сигнатур функций без учета выравнивания. Это означает, что если класс с расширенным выравниванием имеет специфичную для класса функцию выделения без учета выравнивания, то будет вызвана именно эта функция, а не глобальная функция выделения с учетом выравнивания. Это сделано намеренно: предполагается, что член класса лучше знает, как обрабатывать этот класс. |
(since C++17) |
|
При выделении памяти для объектов и массивов объектов, выравнивание которых не превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки выполняется дважды: сначала для сигнатур функций без учета выравнивания, затем для сигнатур функций с учетом выравнивания. |
(since 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[]
с дополнительными пользовательскими параметрами ("placement forms") также могут быть определены как члены класса
(
19-22
)
). Когда выражение размещения
new
с соответствующей сигнатурой ищет соответствующую функцию выделения памяти для вызова, оно начинает поиск в области видимости класса перед изучением глобальной области видимости, и если предоставлен специфичный для класса placement
new
, он вызывается.
|
При выделении памяти для объектов и массивов объектов, выравнивание которых превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки для форм размещения выполняется дважды, так же как и для обычных форм: сначала для сигнатур функций с учетом выравнивания, затем для сигнатур функций без учета выравнивания. |
(since C++17) |
|
При выделении памяти для объектов и массивов объектов, выравнивание которых не превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__ , разрешение перегрузки для форм размещения выполняется дважды, так же как и для обычных форм: сначала для сигнатур функций без учета выравнивания, затем для сигнатур функций с учетом выравнивания. |
(since 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
, и должен иметь два или более параметров. Другими словами, только формы размещения могут быть шаблонами.
Примечания
Хотя неразмещающий placement new ( 9,10 ) не может быть заменён, функция с такой же сигнатурой может быть определена в области видимости класса, как описано выше. Кроме того, разрешены глобальные перегрузки, которые выглядят как placement new , но принимают тип не-void указателя в качестве второго аргумента. Поэтому код, который хочет гарантировать вызов настоящего placement new (например, std::allocator::construct ), должен использовать :: new и также приводить указатель к void * .
Если поведение функции освобождения не удовлетворяет стандартным ограничениям, поведение не определено.
|
Следующие функции должны быть потокобезопасными:
Вызовы этих функций, которые выделяют или освобождают определенную единицу памяти, происходят в едином общем порядке, и каждый такой вызов освобождения happens-before следующего выделения (если таковое имеется) в этом порядке. |
(since 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) | поддержка автономного режима для заменяемого operator new [1] |
0
|
(C++26) | отсутствие поддержки автономного режима | |
__cpp_lib_constexpr_new
|
202406L
|
(C++26) | constexpr размещающий new и new [ ] |
- ↑ Формально, этот макрос раскрывается в 202306L если все стандартные версии заменяемых глобальных функций выделения памяти соответствуют требованиям hosted-реализации.
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| CWG 521 | C++98 |
any class derived from
std::bad_alloc
could be thrown,
even if the std::bad_alloc base is ambiguous or inaccessible |
the exception thrown should match
a handler of type std::bad_alloc |
| LWG 9 | C++98 |
multiple calls for allocating zero
bytes could yield the same pointer |
only allowed if all such previously
yielded pointers have been passed to deallocation functions |
| LWG 206 | C++98 |
replacing the replaceable allocation functions did
not affect the default behaviors of the corresponding replaceable non-throwing allocation functions |
the default behaviors
change accordingly |
| LWG 404 | C++98 |
replacements of the replaceable allocation
functions could be declared inline |
prohibited, no diagnostic required |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
-
- 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++03 (ISO/IEC 14882:2003):
-
- 18.4 Управление динамической памятью [lib.support.dynamic]
- Стандарт C++98 (ISO/IEC 14882:1998):
-
- 18.4 Управление динамической памятью [lib.support.dynamic]
Смотрите также
|
[static]
(C++23)
|
выделяет память с использованием
Allocator
(публичная статическая функция-член
std::generator<Ref,V,Allocator>::promise_type
)
|
|
функции освобождения памяти
(функция) |
|
|
(C++11)
|
получает текущий обработчик new
(функция) |
|
регистрирует новый обработчик
(функция) |
|
|
(устарело в C++17)
(удалено в C++20)
|
получает неинициализированное хранилище
(шаблон функции) |
|
выделяет память
(функция) |
|
|
(C++17)
|
выделяет выровненную память
(функция) |