std::allocate_shared, std::allocate_shared_for_overwrite
Определено в заголовочном файле <memory> | ||
|---|---|---|
template< class T, class Alloc, class... Args > shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args ); | (1) |
(начиная с C++11) (constexpr начиная с C++26) |
template< class T, class Alloc > shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N ); | (2) |
(начиная с C++20) (constexpr начиная с C++26) |
template< class T, class Alloc > shared_ptr<T> allocate_shared( const Alloc& alloc ); | (3) |
(начиная с C++20) (constexpr начиная с C++26) |
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N,
const std::remove_extent_t<T>& u );
| (4) |
(начиная с C++20) (constexpr начиная с C++26) |
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc,
const std::remove_extent_t<T>& u );
| (5) |
(начиная с C++20) (constexpr начиная с C++26) |
template< class T, class Alloc > shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc ); | (6) |
(начиная с C++20) (constexpr начиная с C++26) |
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc,
std::size_t N );
| (7) |
(начиная с C++20) (constexpr начиная с C++26) |
Выделяет память для объекта с помощью копии alloc (перепривязанной к неопределённому value_type) и инициализирует объект переданными аргументами. Возвращает объект std::shared_ptr, управляющий созданным объектом.
T и конструируется так, как если бы был вызван std::allocator_traits<Alloc>::construct(a, pt, (std::forward<Args>(args)...), где pt — указатель std::remove_cv_t<T>* на хранилище, подходящее для размещения объекта типа std::remove_cv_t<T>. Если объект подлежит уничтожению, он уничтожается так, как если бы был вызван std::allocator_traits<Alloc>::destroy(a, pt), где pt — указатель на этот объект типа std::remove_cv_t<T>.a имеет тип Alloc и является копией alloc, возможно перепривязанной. | Эта перегрузка участвует в разрешении перегрузки, только если | (начиная с C++20) |
T является массивом неизвестной границы.T. Каждый элемент имеет значение, заданное по умолчанию.T является массивом известной границы.u.T является массивом неизвестной границы.T. Каждый элемент имеет начальное значение u.T является массивом известной границы.T. - Если
Tне является типом массива, объект конструируется так, как если бы был вызван::new (pv) T, гдеpv— указатель void* на хранилище, подходящее для размещения объекта типаT. Если объект подлежит уничтожению, он уничтожается так, как если бы был вызванpt->~T(), гдеpt— указатель на этот объект типаT. - Если
Tявляется массивом известной границы, начальное значение каждого элемента не определено.
T не является типом массива или является массивом известной границы.T является массивом неизвестной границы. Инициализация и уничтожение элементов массиваВ приведённом ниже описании Элементы массива типа
std::allocator_traits<Alloc>::construct(a, pu) 4,5) std::allocator_traits<Alloc>::construct(a, pu, u) 6,7) ::new (pv) U
Когда срок жизни объекта, которым управляет возвращённый Каждый уничтожаемый элемент массива не-массивного типа std::allocator_traits<Alloc>::destroy(a, pu), где pu — указатель U* на этот элемент массива типа U 6,7) pu->~U(), где pu — указатель на этот элемент массива типа U | (начиная с C++20) |
Параметры
| alloc | - | используемый аллокатор |
| args... | - | список аргументов, с которыми будет сконструирован экземпляр T |
| N | - | используемый размер массива |
| u | - | начальное значение для инициализации каждого элемента массива |
Возвращаемое значение
std::shared_ptr на объект типа T или std::remove_extent_t<T>[N], если T является массивом неизвестной границы(начиная с C++20).
Для возвращённого std::shared_ptr r функция r.get() возвращает ненулевой указатель, а r.use_count() возвращает 1.
Исключения
Могут быть выброшены исключения, выбрасываемые из Alloc::allocate() или конструктора T. Если выбрасывается исключение, (1) не оказывает эффекта. Если при конструировании массива выбрасывается исключение, уже инициализированные элементы уничтожаются в обратном порядке(начиная с C++20).
Примечания
Эти функции обычно выделяют больше памяти, чем sizeof(T), чтобы разместить внутренние структуры учёта, например счётчики ссылок.
Как и std::make_shared, эта функция обычно выполняет только одно выделение памяти и размещает объект T и управляющий блок в выделенном блоке памяти (стандарт рекомендует, но не требует этого; так поступают все известные реализации). Копия alloc хранится в управляющем блоке, чтобы её можно было использовать для освобождения памяти после обнуления счётчиков совместных и слабых ссылок.
В отличие от std::shared_ptr constructors, std::allocate_shared не принимает отдельный пользовательский делетер: переданный аллокатор используется для уничтожения управляющего блока и объекта T, а также для освобождения общего блока памяти, в котором они размещены.
|
| (до C++20) |
Конструктор включает shared_from_this с указателем ptr типа U* означает, что он определяет, имеет ли U однозначный и доступный(начиная с C++17) базовый класс, являющийся специализацией std::enable_shared_from_this, и, если имеет, конструктор вычисляет if(ptr!=nullptr&&ptr->weak_this .expired()).
ptr->weak_this =std::shared_ptr<std::remove_cv_t<U>>
(*this,const_cast<std::remove_cv_t<U>*>(ptr));
Присваивание weak_this не является атомарным и конфликтует с любым потенциально параллельным доступом к тому же объекту. Это гарантирует, что последующие вызовы shared_from_this() будут совместно владеть объектом с std::shared_ptr, созданным этим конструктором из сырого указателя.
Проверка ptr->weak_this .expired() в коде выше гарантирует, что weak_this не будет переназначен, если он уже указывает на владельца. Эта проверка обязательна начиная с C++17.
| Макрос проверки возможностей | Значение | Стандарт | Возможность |
|---|---|---|---|
__cpp_lib_smart_ptr_for_overwrite | 202002L | (C++20) | Создание интеллектуальных указателей с инициализацией по умолчанию (std::allocate_shared_for_overwrite, std::make_shared_for_overwrite, std::make_unique_for_overwrite); перегрузки (6,7) |
Пример
#include <cstddef>
#include <iostream>
#include <memory>
#include <memory_resource>
#include <vector>
class Value
{
int i;
public:
Value(int i) : i(i) { std::cout << "Value(), i = " << i << '\n'; }
~Value() { std::cout << "~Value(), i = " << i << '\n'; }
void print() const { std::cout << "i = " << i << '\n'; }
};
int main()
{
// Create a polymorphic allocator using the monotonic buffer resource
std::byte buffer[sizeof(Value) * 8];
std::pmr::monotonic_buffer_resource resource(buffer, sizeof(buffer));
std::pmr::polymorphic_allocator<Value> allocator(&resource);
std::vector<std::shared_ptr<Value>> v;
for (int i{}; i != 4; ++i)
// Use std::allocate_shared with the custom allocator
v.emplace_back(std::allocate_shared<Value>(allocator, i));
for (const auto& sp : v)
sp->print();
} //< All shared pointers will automatically clean up when they go out of scope.
Вывод:
Value(), i = 0 Value(), i = 1 Value(), i = 2 Value(), i = 3 i = 0 i = 1 i = 2 i = 3 ~Value(), i = 0 ~Value(), i = 1 ~Value(), i = 2 ~Value(), i = 3
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.
| Отчёт об ошибке | Применён к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| LWG 3216 | C++20 |
std::allocate_shared всегда перепривязывал аллокаторперед конструированием и уничтожением объектов | перепривязка необязательна |
| LWG 4024 | C++20 | было неясно, как уничтожаются объекты, сконструированные вstd::allocate_shared_for_overwrite | уточнено |
См. также
создаёт новый shared_ptr (открытая функция-член) |
|
|
(C++20) | создаёт разделяемый указатель, управляющий новым объектом (шаблон функции) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/memory/shared_ptr/allocate_shared