std:: make_shared, std:: make_shared_for_overwrite
|
Определено в заголовочном файле
<memory>
|
||
|
template
<
class
T,
class
...
Args
>
shared_ptr < T > make_shared ( Args && ... args ) ; |
(1) | (начиная с C++11) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( std:: size_t N ) ; |
(2) | (начиная с C++20) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( ) ; |
(3) | (начиная с C++20) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( std:: size_t N, const std:: remove_extent_t < T > & u ) ; |
(4) | (начиная с C++20) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( const std:: remove_extent_t < T > & u ) ; |
(5) | (начиная с C++20) |
|
template
<
class
T
>
shared_ptr < T > make_shared_for_overwrite ( ) ; |
(6) | (начиная с C++20) |
|
template
<
class
T
>
shared_ptr < T > make_shared_for_overwrite ( std:: size_t N ) ; |
(7) | (начиная с C++20) |
Выделяет память для объекта и инициализирует объект предоставленными аргументами. Возвращает std::shared_ptr объект, управляющий вновь созданным объектом.
T
и конструируется как если бы с помощью
::
new
(
pv
)
T
(
std::
forward
<
Args
>
(
args
)
...
)
, где
pv
является указателем
void
*
на хранилище, подходящее для размещения объекта типа
T
. Если объект должен быть уничтожен, он уничтожается как если бы с помощью
pt
-
>
~T
(
)
, где
pt
является указателем на этот объект типа
T
.
|
Эта перегрузка участвует в разрешении перегрузки только если
|
(since C++20) |
T
является типом неограниченного массива.
T
. Каждый элемент имеет значение по умолчанию.
T
является типом ограниченного массива.
T
является типом неограниченного массива.
T
. Каждый элемент имеет начальное значение
u
.
T
является типом ограниченного массива.
T
.
-
Если
Tне является типом массива, объект конструируется как если бы с помощью :: new ( pv ) T , где pv — это указатель void * на память, подходящую для хранения объекта типаT. Если объект должен быть уничтожен, он уничтожается как если бы с помощью pt - > ~T ( ) , где pt — это указатель на данный объект типаT. -
Если
Tявляется типом ограниченного массива, начальное значение для каждого элемента не определено.
T
не является типом массива или является типом ограниченного массива.
T
является типом неограниченного массива.
Инициализация и уничтожение элементов массива
Элементы массива типа
2,3)
::
new
(
pv
)
U
(
)
4,5)
::
new
(
pv
)
U
(
u
)
6,7)
::
new
(
pv
)
U
Когда время жизни объекта, управляемого возвращаемым std::shared_ptr , заканчивается, или когда инициализация элемента массива выбрасывает исключение, инициализированные элементы уничтожаются в обратном порядке их первоначального конструирования.
Для каждого элемента массива не-массивного типа
|
(начиная с C++20) |
Параметры
| 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 .
Исключения
Может выбросить
std::bad_alloc
или любое исключение, выброшенное конструктором
T
. Если исключение выброшено, функции не имеют эффекта.
Если исключение выброшено во время конструирования массива, уже проинициализированные элементы уничтожаются в обратном порядке.
(since C++20)
Примечания
Эти функции обычно выделяют больше памяти, чем sizeof ( T ) чтобы обеспечить место для внутренних структур служебных данных, таких как счетчики ссылок.
Эти функции могут использоваться в качестве альтернативы 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после окончания времени жизни всех shared-владельцев, память, занятаяT, сохраняется до тех пор, пока все weak-владельцы не будут уничтожены, что может быть нежелательно, если 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
однозначный и доступный
(начиная с 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_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 { // конструкторы, необходимые (до C++20) C(int i) : i(i) {} C(int i, float f) : i(i), f(f) {} int i; float f{}; }; int main() { // использование «auto» для типа «sp1» auto sp1 = std::make_shared<C>(1); // перегрузка (1) static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>); std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n"; // явное указание типа “sp2” std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // перегрузка (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 для value-инициализированного float[64]; перегрузка (2): std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64); // shared_ptr для value-инициализированного long[5][3][4]; перегрузка (2): std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5); // shared_ptr для value-initialized short[128]; перегрузка (3): std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>(); // shared_ptr на value-инициализированный int[7][6][5]; перегрузка (3): std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>(); // shared_ptr для double[256], где каждый элемент равен 2.0; перегрузка (4): std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0); // shared_ptr для double[7][2], где каждый double[2] // element is {3.0, 4.0}; перегрузка (4): std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0}); // shared_ptr на vector<int>[4], где каждый вектор // содержит элементы {5, 6}; перегрузка (4): std::shared_ptr<std::vector<int>[]> sp9 = std::make_shared<std::vector<int>[]>(4, {5, 6}); // shared_ptr для float[512], где каждый элемент равен 1.0; перегрузка (5): std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0); // shared_ptr для double[6][2], где каждый элемент double[2] // is {1.0, 2.0}; перегрузка (5): std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0}); // shared_ptr на vector<int>[4], где каждый вектор // содержит элементы {5, 6}; перегрузка (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 }
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 4024 | C++20 |
было неясно, как уничтожаются объекты, созданные в
std::make_shared_for_overwrite
|
прояснено |
Смотрите также
создает новый
shared_ptr
(публичная функция-член) |
|
|
создает умный указатель, который управляет новым объектом, выделенным с использованием аллокатора
(шаблон функции) |
|
|
(C++11)
|
позволяет объекту создавать
shared_ptr
ссылающийся на себя
(шаблон класса) |
|
(C++14)
(C++20)
|
создает уникальный указатель, который управляет новым объектом
(шаблон функции) |
|
функции выделения памяти
(функция) |