Spec-Zone.ru › C++

operator new, operator new[]

Определено в заголовке <new>
функции замещающей аллокации

[[nodiscard]]

(с C++20)
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)
функции замещающей безбросковой аллокации

noexcept

(с C++11)

[[nodiscard]]

(с C++20)
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)
функции замещающей аллокации без выделения памяти

noexcept

(с C++11)

[[nodiscard]]

(с C++20)
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 для выделения памяти, в которой затем будет инициализирован новый объект. Они также могут быть вызваны с использованием обычной синтаксической конструкции вызова функций.

1) Вызывается не массивом выражениями new для выделения памяти, необходимой для одного объекта. Реализация стандартной библиотеки выделяет count байт из свободного пространства. В случае неудачи, реализация стандартной библиотеки вызывает указатель функции, возвращённый std::get_new_handler, и повторяет попытки выделения, пока обработчик new не вернёт значение или не станет нулевым указателем, в котором случае бросается исключение std::bad_alloc. Эта функция должна возвращать указатель, соответствующий выравниванию к объекту запрошенного размера.
2) Вызывается выражениями new[] для выделения всей памяти, необходимой для массива (включая возможные накладные расходы выражения new). Реализация стандартной библиотеки вызывает версию (1).
3) Вызывается не массивом выражениями new для выделения памяти, необходимой для одного объекта, если требования к выравниванию превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__.
4) Вызывается выражениями new[] для выделения всей памяти, необходимой для массива объектов, если требования к выравниванию превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__.
5) Вызывается не бросающими исключения выражениями new. Реализация стандартной библиотеки вызывает версию (1) и возвращает нулевой указатель при ошибке вместо распространения исключения.
6) Вызывается не бросающими исключения выражениями new[]. Реализация стандартной библиотеки вызывает версию (2) и возвращает нулевой указатель при ошибке вместо распространения исключения.
7) Вызывается не бросающими исключения выражениями new, если требования к выравниванию объекта превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__. Реализация стандартной библиотеки вызывает версию (3) и возвращает нулевой указатель при ошибке вместо распространения исключения.
8) Вызывается не бросающими исключения выражениями new[], если требования к выравниванию элементов массива превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__. Реализация стандартной библиотеки вызывает версию (4) и возвращает нулевой указатель при ошибке вместо распространения исключения.
9) Вызывается выражением placement new. Реализация стандартной библиотеки не выполняет никаких действий и возвращает ptr без изменений. Поведение не определено, если эта функция вызывается через выражение placement new и ptr — нулевой указатель.
10) Вызывается выражением placement new для массива. Реализация стандартной библиотеки не выполняет никаких действий и возвращает ptr без изменений. Поведение не определено, если эта функция вызывается через выражение placement new и ptr — нулевой указатель.
11) При определении, вызывается выражением placement new с соответствующей сигнатурой. Если определена версия класса (19), она вызывается в приоритете перед (11). Если ни (11), ни (19) не предоставлены пользователем, выражение placement new некорректно.
12) При определении, вызывается выражением placement new для массива с соответствующей сигнатурой. Если определена версия класса (20), она вызывается в приоритете перед (12). Если ни (12), ни (20) не предоставлены пользователем, выражение placement new некорректно.
13) При определении, вызывается выражением placement new с соответствующей сигнатурой, если требования к выравниванию объекта превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__. Если определена версия класса (15) или (17), она вызывается вместо неё. Если не указана ни класс-специфичная, ни глобальная версия с учётом выравнивания, то используется версия без учёта выравнивания (11).
14) При определении, вызывается выражением placement new для массива с соответствующей сигнатурой, если требования к выравниванию элемента превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__. Если определена версия класса (16) или (18), она вызывается вместо неё. Если не указана ни класс-специфичная, ни глобальная версия с учётом выравнивания, то используется версия без учёта выравнивания (12).
15) При определении, вызывается обычным выражением new при выделении объекта типа T.
16) При определении, вызывается обычным выражением new[] при выделении массива объектов типа T.
17) При определении, вызывается обычным выражением new при выделении объекта типа T, если его требования к выравниванию превышают __STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не указан, но указана версия без учёта выравнивания (15), вызывается версия без учёта выравнивания.
18) Если определено, вызывается обычным выражением new[], если выделяется массив объектов типа T, если его требование к выравниванию превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не предоставлен, но перегрузка член-функции без учета выравнивания (16) — есть, используется перегрузка члена-функции без учета выравнивания.
19) Если определено, вызывается пользовательским выражением placement new для одиночного объекта с соответствующей сигнатурой, если выделяется объект типа T.
20) Если определено, вызывается пользовательским выражением placement new[] с соответствующей сигнатурой, если выделяется массив объектов типа T.
21) Если определено, вызывается пользовательским выражением placement new для одиночного объекта с соответствующей сигнатурой, если выделяется объект типа T, если его требование к выравниванию превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не предоставлен, но перегрузка член-функции без учета выравнивания (19) — есть, используется перегрузка члена-функции без учета выравнивания.
22) Если определено, вызывается пользовательским выражением placement new[] с соответствующей сигнатурой, если выделяется массив объектов типа T, если его требование к выравниванию превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__. Если этот перегруз не предоставлен, но перегрузка член-функции без учета выравнивания (20) — есть, используется перегрузка члена-функции без учета выравнивания.

Параметры

count - количество байтов для выделения
ptr - указатель на область памяти для инициализации объекта
tag - метка разбора, используемая для выбора перегрузок без исключений
al - выравнивание для использования. Поведение неопределено, если это не допустимое значение выравнивания

Возвращаемое значение

1-4) Если выделение прошло успешно, ненулевой указатель p0 , который указывает на подходяще выровненную память размером не менее size и отличается от любого ранее возвращенного значения p1, если это значение p1 не было затем передано в заменяемую функцию освобождения памяти; если выделение не удалось, не возвращает (исключение выбрасывается, см. ниже).
5-8) То же, что (1-4), но возвращает нулевой указатель, если выделение не удалось.
9,10) ptr
11-22) То же, что (1-4), если функция не возвращает при неудачном выделении, в противном случае то же, что (5-8).

Исключение

1-4) Выбрасывает исключение типа, который соответствовал бы обработчику типа std::bad_alloc при неудачном выделении памяти.
11-22) То же, что (1-4), если функция не возвращает при неудачном выделении, в противном случае то же, что (5-8).

Глобальные замены

Версии (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, которые пытаются выделить объекты этого класса.

При выделении объектов и массивов объектов, выравнивание которых превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__, разрешение перегрузки выполняется дважды: сначала для функций с учетом выравнивания, затем для функций без учета выравнивания. Это означает, что если класс с расширенным выравниванием имеет класс-специфическую функцию выделения без учета выравнивания, будет вызвана именно эта функция, а не глобальная функция выделения с учетом выравнивания. Это сделано намеренно: ожидается, что член класса лучше всего знает, как обработать этот класс.

(с C++17)

При выделении объектов и массивов объектов, выравнивание которых не превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__, разрешение перегрузки выполняется дважды: сначала для функций без учета выравнивания, затем для функций с учетом выравнивания.

(с 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, она вызывается.

END_OF_DOCUMENT_MARKER

При выделении объектов и массивов объектов, выравнивание которых превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__, разрешение перегрузки для размещаемых форм выполняется дважды так же, как и для обычных форм: сначала для функций с учетом выравнивания, затем для функций без учета выравнивания.

(с C++17)

При выделении объектов и массивов объектов, выравнивание которых не превышает __STDCPP_DEFAULT_NEW_ALIGNMENT__, разрешение перегрузки для размещаемых форм выполняется дважды, как и для обычных форм: сначала для функций без учета выравнивания, затем для функций с учетом выравнивания.

(с 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*.

Если поведение функции освобождения не удовлетворяет стандартным ограничениям, такое поведение неопределенно.

Следующие функции должны быть потокобезопасными:

  • Библиотечные версии operator new и operator delete
  • Заменённые пользователем версии глобальных operator new и operator delete
  • std::calloc, std::malloc, std::realloc, std::aligned_alloc(с C++17), std::free

Вызовы этих функций, которые выделяют или освобождают определенный блок памяти, происходят в едином общем порядке, и каждый вызов освобождения предшествует следующему выделению (если оно есть) в этом порядке.

(с 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) Отсутствует поддержка свободных операторов
  1. Формально, эта макрокоманда расширяется до 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]

См. также

operator deleteoperator delete[]
функции освобождения
(функция)
get_new_handler
(C++11)
получает текущий обработчик new
(функция)
set_new_handler
регистрирует обработчик new
(функция)
get_temporary_buffer
(устарело в C++17)(удалено в C++20)
получает неинициализированный блок памяти
(шаблон функции)
malloc
выделяет память
(функция)
aligned_alloc
(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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API