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, /* args... */ );
|
(11) | |
void* operator new[]( std::size_t count, /* args... */ );
|
(12) | |
void* operator new ( std::size_t count,
std::align_val_t al, /* args... */ );
|
(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, /* args... */ );
|
(19) | |
void* T::operator new[]( std::size_t count, /* args... */ );
|
(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, /* args... */ );
|
(22) | (начиная с C++17) |
Пытается выделить запрошенное количество байт; запрос на выделение может завершиться неудачей (даже если запрошенное количество байт равно нулю). Эти функции выделения вызываются new выражениями для выделения памяти, в которой затем будет инициализирован новый объект. Их также можно вызывать с помощью обычного синтаксиса вызова функции.
new выражениями. Не выполняют никаких действий и возвращают ptr без изменений.new и ptr является нулевым указателем, поведение не определено.new выражениями.Перегрузки (1-4) неявно объявляются в каждой единице трансляции, даже если заголовок <new> не включён.
См. new выражение для критериев выбора перегрузки.
Параметры
| count | - | количество байт для выделения |
| ptr | - | указатель на область памяти для инициализации объекта |
| tag | - | тег устранения неоднозначности для выбора непорождающих исключения перегрузок |
| al | - | выравнивание для использования, недопустимое значение приводит к неопределенному поведению |
Возвращаемое значение
Исключения
Глобальные замены
Перегрузки (1–8) являются заменяемыми. Действия версий по умолчанию:
- Если попытка успешна, возвращает указатель на выделенную память, память выровнена по фундаментальному выравниванию(до C++17)память выровнена по
__STDCPP_DEFAULT_NEW_ALIGNMENT__(начиная с C++17). - В противном случае, если в данный момент не установлен new-handler, генерирует std::bad_alloc.
- В противном случае вызывает установленный new-handler.
- Если new-handler возвращает управление, начинает новую попытку выделения.
- В противном случае завершает текущий вызов.
operator new(count).al.operator new(count, al).tag.
- Если вызов возвращает управление в обычном порядке, возвращает результат этого вызова.
- В противном случае возвращает нулевой указатель.
|
В автономных реализациях определяется реализацией, удовлетворяют ли версии по умолчанию (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) стандартной библиотеки не могут быть заменены и могут быть настроены только в том случае, если размещающее new выражение не использовало синтаксис ::new, путём предоставления размещающей new (19,20) с соответствующей сигнатурой: void* T::operator new(std::size_t, void*) или void* T::operator new[](std::size_t, void*).
|
Размещающая форма |
(начиная с 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)). Когда выражение 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 и должна иметь два или более параметров. Другими словами, шаблонами могут быть только размещающие формы.
Примечания
Хотя неразмещающий 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)
|
выделяет выровненную память
(функция) |