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-выражениями для выделения памяти, в которой затем будет инициализирован новый объект. Их также можно вызывать с помощью обычного синтаксиса вызова функции.
ptr без изменений.ptr является нулевым указателем, поведение не определено.Перегрузки (1-4) неявно объявляются в каждой единице трансляции, даже если заголовок <new> не включен.
Критерии выбора перегрузки см. в описании new-выражения.
Параметры
| count | - | количество байтов для выделения |
| ptr | - | указатель на область памяти, в которой нужно инициализировать объект |
| tag | - | тег для устранения неоднозначности, используемый для выбора небросающих исключения перегрузок |
| al | - | используемое выравнивание; недопустимое значение приводит к неопределенному поведению |
Возвращаемое значение
p0, указывающий на выровненную соответствующим образом область памяти размером не менее size и отличный от любого ранее возвращенного значения p1, если только это значение p1 впоследствии не было передано заменяемой функции освобождения памяти; если выделение памяти завершилось неудачей, не возвращает управление (выбрасывается исключение; см. ниже).ptr
Исключения
std::bad_alloc.Глобальные замены
Перегрузки (1-8) являются заменяемыми. Эффекты версий по умолчанию:
1) Пытается выделить запрошенную область памяти. Не определено, включает ли эта попытка вызовstd::malloc или std::aligned_alloc. - Если попытка успешна, возвращает указатель на выделенную область памяти; память выровнена по фундаментальному выравниванию(до C++17)память выровнена по
__STDCPP_DEFAULT_NEW_ALIGNMENT__(начиная с C++17). - В противном случае, если в данный момент не установлен обработчик new, выбрасывает
std::bad_alloc. - В противном случае вызывает установленный в данный момент обработчик new.
- Если обработчик new возвращает управление, начинает новую попытку выделения памяти.
- В противном случае завершает текущий вызов.
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[] с дополнительными пользовательскими параметрами («формы размещения») могут, как обычно, объявляться в глобальной области видимости и вызываются соответствующими формами размещения new-выражений.
Невыделяющие формы размещения operator new стандартной библиотеки (9,10) нельзя заменять; их можно настроить, только если в размещающем new-выражении не использован синтаксис ::new, определив соответствующую по сигнатуре специфичную для класса функцию размещения new (19,20): void*T::operatornew(std::size_t,void*) или void*T::operatornew[](std::size_t,void*).
| Форма размещения void*operatornew(std::size_t,std::size_t) не допускается, поскольку соответствующая сигнатура функции освобождения памяти, voidoperatordelete(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). Когда размещающее 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) | поддержка заменяемого operatornew в автономных реализациях[1] |
0 | (C++26) | поддержка в автономных реализациях отсутствует | |
__cpp_lib_constexpr_new | 202406L | (C++26) | размещающие new и new[] с constexpr |
- Формально этот макрос раскрывается в
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: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) | выделяет выровненную память (функция) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/memory/new/operator_new