std::make_shared, std::make_shared_for_overwrite
Определено в заголовочном файле <memory> | ||
|---|---|---|
template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args ); | (1) | (с C++11) (T не является массивом) |
template< class T > shared_ptr<T> make_shared( std::size_t N ); | (2) |
(с C++20) (T является U[]) |
template< class T > shared_ptr<T> make_shared(); | (3) | (с C++20) (T является U[N]) |
template< class T > shared_ptr<T> make_shared( std::size_t N, const std::remove_extent_t<T>& u ); | (4) | (с C++20) (T является U[]) |
template< class T > shared_ptr<T> make_shared( const std::remove_extent_t<T>& u ); | (5) | (с C++20) (T является U[N]) |
template< class T > shared_ptr<T> make_shared_for_overwrite(); | (6) |
(с C++20) (T не является U[]) |
template< class T > shared_ptr<T> make_shared_for_overwrite( std::size_t N ); | (7) | (с C++20) (T является U[]) |
T и оборачивает его в std::shared_ptr, используя args в качестве списка параметров для конструктора T. Объект создаётся так, как если бы по выражению ::new (pv) T(std::forward<Args>(args)...), где pv — внутренний указатель void* на область памяти, подходящую для хранения объекта типа T. Область памяти обычно больше, чем sizeof(T), чтобы использовать одно выделение для блока управления общим указателем и объекта T. Конструктор std::shared_ptr вызываемый этой функцией, позволяет shared_from_this получить указатель на недавно созданный объект типа T. | Этот перегруз участвует в разрешении перегрузки только если T не является типом массива. | (с C++20) |
std::remove_all_extents_t<T> инициализируются по умолчанию, как если бы по выражению placement-new ::new(pv) std::remove_all_extents_t<T>(). Перегрузка (2) создаёт массив размером N по первой размерности. Элементы массива инициализируются в порядке возрастания их адресов, а по окончании их жизненного цикла уничтожаются в обратном порядке их первоначального создания.u. Если U не является типом массива, то это выполняется так же, как по тому же выражению placement-new, что и в (1); в противном случае это выполняется так, как если бы каждый не-массивовый элемент (возможно многомерного) массива инициализировался соответствующим элементом из u с тем же выражением placement-new, что и в (1). Перегрузка (4) создаёт массив размером N по первой размерности. Элементы массива инициализируются в порядке возрастания их адресов, а по окончании их жизненного цикла уничтожаются в обратном порядке их первоначального создания.T не является типом массива, и (3), если T является U[N], за исключением того, что создаваемый объект инициализируется по умолчанию.В каждом случае объект (или отдельные элементы, если T является типом массива)(с C++20) будет уничтожен p->~X(), где p — указатель на объект и X — его тип.
Параметры
| args | - | список аргументов, с помощью которых будет создан экземпляр T |
| N | - | размер массива |
| u | - | начальное значение для инициализации каждого элемента массива |
Возвращаемое значение
Указатель на экземпляр типа T.
Исключение
Может выбросить std::bad_alloc или любое исключение, выброшенное конструктором T. Если выброшено исключение, функции не имеют эффекта. Если во время создания массива происходит выброс исключения, уже инициализированные элементы уничтожаются в обратном порядке.(с C++20)
Примечания
Эта функция может быть использована как альтернатива std::shared_ptr<T>(new T(args...)). Компромиссы следующие:
-
std::shared_ptr<T>(new T(args...))выполняет как минимум два выделения (одно для объектаTи одно для блока управления общим указателем), в то время какstd::make_shared<T>обычно выполняет только одно выделение (стандарт рекомендует, но не требует этого; все известные реализации делают это). - Если какие-либо
std::weak_ptrссылаются на блок управления, созданныйstd::make_sharedпосле окончания жизненного цикла всех общих владельцев, то память, занимаемаяT, сохраняется до тех пор, пока все слабые владельцы не будут уничтожены, что может быть нежелательно, еслиsizeof(T)большой. -
std::shared_ptr<T>(new T(args...))может вызвать непубличный конструкторTесли выполняется в контексте, где он доступен, в то время какstd::make_sharedтребует публичного доступа к выбранному конструктору. - В отличие от конструкторов
std::shared_ptr,std::make_sharedне позволяет настраивать удалитель. -
std::make_sharedиспользует::new, поэтому, если какие-либо специальные особенности были настроены с помощью класса-специфическогоoperator new, они будут отличаться отstd::shared_ptr<T>(new T(args...)).
| (до C++20) |
| (до C++17) |
Конструктор разрешает shared_from_this с указателем ptr типа U* означает, что он определяет, имеет ли U недвусмысленную и доступную базовый класс, который является специализацией 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 — скрытое изменяемое член std::weak_ptr объекта std::enable_shared_from_this. Присвоение члену weak_this не является атомарным и конфликтует с любым потенциальным одновременным доступом к тому же объекту. Это гарантирует, что будущие вызовы shared_from_this() будут разделять владение с std::shared_ptr созданным этим указателем.
Тест ptr->weak_this.expired() в примере кода выше гарантирует, что weak_this не переприсваивается, если он уже указывает на владельца. Этот тест необходим начиная с C++17.
| Макрос проверки наличия функции | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_lib_shared_ptr_arrays | 201707L | (C++20) | Поддержка массивов в std::make_shared; перегрузки (2-5) |
__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 <iostream>
#include <memory>
#include <type_traits>
#include <vector>
struct C
{
// constructors needed (until C++20)
C(int i) : i(i) {}
C(int i, float f) : i(i), f(f) {}
int i;
float f{};
};
int main()
{
// using `auto` for the type of `sp1`
auto sp1 = std::make_shared<C>(1); // overload (1)
static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>);
std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n";
// being explicit with the type of `sp2`
std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // overload (1)
static_assert(std::is_same_v<decltype(sp2), std::shared_ptr<C>>);
static_assert(std::is_same_v<decltype(sp1), decltype(sp2)>);
std::cout << "sp2->{ i:" << sp2->i << ", f:" << sp2->f << " }\n";
// shared_ptr to a value-initialized float[64]; overload (2):
std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64);
// shared_ptr to a value-initialized long[5][3][4]; overload (2):
std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5);
// shared_ptr to a value-initialized short[128]; overload (3):
std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>();
// shared_ptr to a value-initialized int[7][6][5]; overload (3):
std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>();
// shared_ptr to a double[256], where each element is 2.0; overload (4):
std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0);
// shared_ptr to a double[7][2], where each double[2]
// element is {3.0, 4.0}; overload (4):
std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0});
// shared_ptr to a vector<int>[4], where each vector
// has contents {5, 6}; overload (4):
std::shared_ptr<std::vector<int>[]> sp9 =
std::make_shared<std::vector<int>[]>(4, {5, 6});
// shared_ptr to a float[512], where each element is 1.0; overload (5):
std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0);
// shared_ptr to a double[6][2], where each double[2] element
// is {1.0, 2.0}; overload (5):
std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0});
// shared_ptr to a vector<int>[4], where each vector
// has contents {5, 6}; overload (5):
std::shared_ptr<std::vector<int>[4]> spC =
std::make_shared<std::vector<int>[4]>({5, 6});
}Вывод:
sp1->{ i:1, f:0 }
sp2->{ i:2, f:3 }См. также
создаёт новый shared_ptr (публичный член-функция) |
|
|
(C++20) | создаёт умный указатель, управляющий новым объектом, выделенным с помощью аллокатора (шаблон функции) |
|
(C++11) | позволяет объекту создать shared_ptr , ссылающийся на себя (шаблон класса) |
|
(C++14)(C++20) | создаёт уникальный указатель, управляющий новым объектом (шаблон функции) |
| функции выделения памяти (функция) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared