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
는
T
타입의 객체를 보관하기에 적합한 저장 공간을 가리키는
void
*
포인터입니다. 객체가 파괴되어야 하는 경우, 다음과 같이 파괴됩니다:
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
의 생성자에 의해 던져지는 모든 예외를 던질 수 있습니다. 예외가 발생하면 함수는 아무런 효과를 가지지 않습니다.
배열 생성 중 예외가 발생하면, 이미 초기화된 요소들은 역순으로 소멸됩니다.
(C++20부터)
참고 사항
이러한 함수들은 일반적으로 내부 기록 관리 구조(예: 참조 카운트)를 허용하기 위해 sizeof ( T ) 보다 더 많은 메모리를 할당합니다.
이러한 함수들은 std:: shared_ptr < T > ( new T ( args... ) ) 의 대안으로 사용될 수 있습니다. 장단점은 다음과 같습니다:
-
std::
shared_ptr
<
T
>
(
new T
(
args...
)
)
는 최소 두 번의 할당(객체
T용 한 번과 shared pointer의 제어 블록용 한 번)을 수행하는 반면, std :: make_shared < T > 는 일반적으로 단 한 번의 할당만 수행합니다(표준에서 이를 권장하지만 요구하지는 않으며, 알려진 모든 구현체들이 이렇게 동작합니다). -
모든 shared 소유자의 수명이 끝난 후에도
std::make_shared로 생성된 제어 블록을 참조하는 std::weak_ptr 이 존재한다면,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() { // "sp1"의 타입에 "auto" 사용 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"; // 값-초기화된 float[64]에 대한 shared_ptr; 오버로드 (2): std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64); // 값-초기화된 long[5][3][4]에 대한 shared_ptr; 오버로드 (2): std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5); // 값-초기화된 short[128]에 대한 shared_ptr; 오버로드 (3): std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>(); // 값-초기화된 int[7][6][5]에 대한 shared_ptr; 오버로드 (3): std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>(); // double[256]에 대한 shared_ptr, 각 요소는 2.0; 오버로드 (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 // 내용이 {5, 6}임; 오버로드 (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 // 내용이 {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 | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| LWG 4024 | C++20 |
std::make_shared_for_overwrite
에서 생성된 객체가
어떻게 파괴되는지 불분명했음 |
명확히 규정됨 |
참고 항목
새로운
shared_ptr
을 생성함
(public member function) |
|
|
할당자를 사용하여 할당된 새 객체를 관리하는 shared pointer를 생성함
(function template) |
|
|
(C++11)
|
객체가 자신을 참조하는
shared_ptr
을 생성할 수 있도록 함
(class template) |
|
(C++14)
(C++20)
|
새 객체를 관리하는 unique pointer를 생성함
(function template) |
|
할당 함수들
(function) |