Namespaces
Variants

std::shared_ptr<T>:: shared_ptr

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
constexpr shared_ptr ( ) noexcept ;
(1)
constexpr shared_ptr ( std:: nullptr_t ) noexcept ;
(2)
template < class Y >
explicit shared_ptr ( Y * ptr ) ;
(3)
template < class Y, class Deleter >
shared_ptr ( Y * ptr, Deleter d ) ;
(4)
template < class Deleter >
shared_ptr ( std:: nullptr_t ptr, Deleter d ) ;
(5)
template < class Y, class Deleter, class Alloc >
shared_ptr ( Y * ptr, Deleter d, Alloc alloc ) ;
(6)
template < class Deleter, class Alloc >
shared_ptr ( std:: nullptr_t ptr, Deleter d, Alloc alloc ) ;
(7)
template < class Y >
shared_ptr ( const shared_ptr < Y > & r, element_type * ptr ) noexcept ;
(8)
template < class Y >
shared_ptr ( shared_ptr < Y > && r, element_type * ptr ) noexcept ;
(8) (C++20 이후)
shared_ptr ( const shared_ptr & r ) noexcept ;
(9)
template < class Y >
shared_ptr ( const shared_ptr < Y > & r ) noexcept ;
(9)
shared_ptr ( shared_ptr && r ) noexcept ;
(10)
template < class Y >
shared_ptr ( shared_ptr < Y > && r ) noexcept ;
(10)
template < class Y >
explicit shared_ptr ( const std:: weak_ptr < Y > & r ) ;
(11)
template < class Y >
shared_ptr ( std:: auto_ptr < Y > && r ) ;
(12) (C++17에서 제거됨)
template < class Y, class Deleter >
shared_ptr ( std:: unique_ptr < Y, Deleter > && r ) ;
(13)

다양한 포인터 타입으로부터 관리할 객체를 참조하는 shared_ptr 을 생성합니다.

아래 설명의 목적상, 포인터 타입 Y* 은 다음 중 하나의 경우에 포인터 타입 T* 호환된다 고 합니다: Y* T* 로 변환 가능한 경우, 또는 Y 가 배열 타입 U[N] 이고 T U cv [] 인 경우 (여기서 cv는 일부 cv-qualifiers 집합임).

(since C++17)
1,2) 관리되는 객체가 없는 shared_ptr 을 생성합니다. 즉, 빈 shared_ptr 입니다.
3-7) 관리 객체에 대한 포인터로 shared_ptr ptr 과 함께 생성합니다.

(3,4,6) 의 경우, Y* T* 로 변환 가능해야 합니다.

(C++17 이전)

만약 T 가 배열 타입 U[N] 인 경우, Y(*)[N] 이 유효하지 않은 타입이거나 T* 로 변환 불가능할 때 (3,4,6) 은 오버로드 해결에 참여하지 않습니다. 만약 T 가 배열 타입 U[] 인 경우, Y(*)[] 이 유효하지 않은 타입이거나 T* 로 변환 불가능할 때 (3,4,6) 은 오버로드 해결에 참여하지 않습니다. 그 외의 경우, Y* T* 로 변환 불가능할 때 (3,4,6) 은 오버로드 해결에 참여하지 않습니다.

(C++17 이후)
추가적으로:
3) 다음을 삭제자로 사용합니다: delete-expression delete ptr T 가 배열 타입이 아닌 경우; delete [ ] ptr T 가 배열 타입인 경우 (C++17부터) . Y 는 완전한 타입이어야 합니다. delete 표현식은 올바른 형식이어야 하며, 잘 정의된 동작을 가지며 어떤 예외도 던지지 않아야 합니다. 이 생성자는 추가적으로 delete 표현식이 올바른 형식이 아닌 경우 오버로드 해결에 참여하지 않습니다. (C++17부터)
4,5) 지정된 삭제자 d 를 삭제자로 사용합니다. d ( ptr ) 표현식은 올바르게 형성되어야 하며, 잘 정의된 동작을 가져야 하고 어떤 예외도 던지지 않아야 합니다. d 와 이로부터 복사된 저장된 삭제자의 생성은 예외를 던지지 않아야 합니다.

Deleter CopyConstructible 요구 사항을 충족해야 합니다.

(C++17 이전)

이러한 생성자들은 추가적으로 d ( ptr ) 표현식이 올바르게 형성되지 않거나, std:: is_move_constructible_v < D > false 인 경우 오버로드 해결에 참여하지 않습니다.

(C++17 이후)
6,7) (4,5) 와 동일하지만, 내부 사용을 위한 데이터 할당에 alloc 의 사본을 추가적으로 사용합니다. Alloc Allocator 여야 합니다.
8) 별칭 생성자 : shared_ptr 을 생성하며, 이는 r 의 초기값과 소유권 정보를 공유하지만, 관련 없고 관리되지 않는 포인터 ptr 를 보유합니다. 이 shared_ptr 이 그룹에서 범위를 벗어나는 마지막 포인터인 경우, 원래 r 에 의해 관리되던 객체에 대해 저장된 삭제자를 호출합니다. 그러나 이 shared_ptr 에서 get() 을 호출하면 항상 ptr 의 복사본을 반환합니다. 프로그래머는 이 ptr 이 shared_ptr이 존재하는 동안 유효하게 유지되도록 보장할 책임이 있으며, 이는 일반적인 사용 사례에서 ptr r 에 의해 관리되는 객체의 멤버이거나 r.get() 의 별칭(예: 다운캐스트)인 경우에 해당합니다. rvalue를 취하는 두 번째 오버로드의 경우, r 은 비어 있고 호출 후 r. get ( ) == nullptr 입니다. (C++20부터)
9) r 가 관리하는 객체의 소유권을 공유하는 shared_ptr 을 생성합니다. r 가 객체를 관리하지 않으면, * this 도 객체를 관리하지 않습니다. 템플릿 오버로드는 Y* 암시적으로 변환 가능하지 않으면 (C++17 이전) 호환되지 않으면 (C++17 이후) 오버로드 해결에 참여하지 않습니다.
10) shared_ptr r 에서 이동 생성합니다. 생성 후, * this r 의 이전 상태 사본을 포함하며, r 는 비어 있고 저장된 포인터는 null입니다. 템플릿 오버로드는 Y* 암시적으로 변환 가능하지 않으면 (C++17 이전) 호환되지 않으면 (C++17 이후) T* 로 오버로드 해결에 참여하지 않습니다.
11) r 가 관리하는 객체의 소유권을 공유하는 shared_ptr 을 생성합니다. Y* T* 로 암시적으로 변환 가능해야 합니다. (C++17 이전) 이 오버로드는 Y* T* 와 호환될 때만 오버로드 해결에 참여합니다. (C++17 이후) 동일한 목적으로 r. lock ( ) 를 사용할 수 있습니다: 차이점은 이 생성자는 인자가 비어 있을 때 예외를 던지는 반면, std:: weak_ptr < T > :: lock ( ) 는 그 경우 빈 std::shared_ptr 을 생성한다는 점입니다.
12) 이전에 r 이 소유하던 객체를 저장하고 소유하는 shared_ptr 을 생성합니다. Y* T* 로 변환 가능해야 합니다. 생성 후에는 r 이 비어 있게 됩니다.
13) r 가 현재 관리하는 객체를 관리하는 shared_ptr 을 생성합니다. r 와 연관된 deleter는 향후 관리 객체 삭제를 위해 저장됩니다. 호출 후 r 는 어떤 객체도 관리하지 않습니다.
std::unique_ptr<Y, Deleter>::pointer compatible with T* 가 아닌 경우, 이 오버로드는 오버로드 해결에 참여하지 않습니다. 만약 r. get ( ) 이 null 포인터라면, 이 오버로드는 기본 생성자 (1) 와 동등합니다. (since C++17)
만약 Deleter 가 참조 타입이라면, 이는 shared_ptr ( r. release ( ) , std:: ref ( r. get_deleter ( ) ) 와 동등합니다. 그렇지 않다면, shared_ptr ( r. release ( ) , std :: move ( r. get_deleter ( ) ) ) 와 동등합니다.

T 가 배열 타입이 아닐 때, 오버로드 (3,4,6) shared_from_this ptr 와 함께 사용 가능하게 하며, 오버로드 (13) shared_from_this r. release ( ) 가 반환하는 포인터와 함께 사용 가능하게 합니다.

목차

매개변수

ptr - 관리할 객체에 대한 포인터
d - 객체를 파괴하는 데 사용할 삭제자
alloc - 내부 사용을 위한 데이터 할당에 사용할 할당자
r - 소유권을 공유하거나 획득할 다른 스마트 포인터

사후 조건

1,2) use_count() 0 이고 get() nullptr 입니다.
3-7) use_count() 1 이고 get() ptr 과 같습니다.
8) get() ptr 과 같습니다. 두 번째 오버로드의 경우, r 은 비어 있고 r. get ( ) nullptr 과 같습니다.
9) get() r. get ( ) 와 같고 use_count() r. use_count ( ) 와 같다.
10) r 는 비어 있어야 하고 r. get ( ) nullptr 와 같아야 하며, * this r 의 이전 값이어야 합니다.
11) use_count() r. use_count ( ) 와 같습니다.
12) use_count() 1 이고 r. get ( ) nullptr 입니다.

예외

3) std::bad_alloc 필요한 추가 메모리를 확보할 수 없는 경우. 다른 오류에 대해서는 구현에서 정의된 예외를 던질 수 있습니다. 예외가 발생하면, 이는 delete ptr T 가 배열 타입이 아닌 경우 호출하고, 그렇지 않으면 delete [ ] ptr 를 호출합니다 (C++17부터) .
4-7) std::bad_alloc 필요한 추가 메모리를 확보할 수 없는 경우. 다른 오류에 대해서는 구현에서 정의된 예외를 던질 수 있습니다. d ( ptr ) 예외가 발생하면 호출됩니다.
11) std::bad_weak_ptr 만약 r. expired ( ) == true 인 경우. 이 경우 생성자는 아무런 효과가 없습니다.
12) std::bad_alloc 필요한 추가 메모리를 확보할 수 없는 경우. 다른 오류에 대해서는 구현에서 정의된 예외를 던질 수 있습니다. 예외가 발생하면 이 생성자는 아무런 효과를 가지지 않습니다.
13) 예외가 발생하면 생성자는 아무런 효과를 가지지 않습니다.

참고 사항

생성자가 shared_from_this 을 활성화한다는 것은 U* 타입의 포인터 ptr 을 사용하여 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() 호출이 이 raw 포인터 생성자로 생성된 std::shared_ptr 와 소유권을 공유하도록 보장합니다.

위 코드의 테스트 ptr - > weak_this  . expired ( ) weak_this 가 이미 소유자를 가리키고 있을 경우 재할당되지 않도록 보장합니다. 이 테스트는 C++17부터 필수적으로 요구됩니다.

원시 포인터 오버로드는 가리키는 객체의 소유권을 가정합니다. 따라서 이미 shared_ptr 에 의해 관리되는 객체에 대해 원시 포인터 오버로드를 사용하여 shared_ptr 을 생성하는 것은(예: shared_ptr ( ptr. get ( ) ) ), 해당 객체가 std::enable_shared_from_this 에서 파생된 타입인 경우에도 정의되지 않은 동작을 초래할 가능성이 높습니다.

기본 생성자가 constexpr 이므로, 정적 shared_ptr들은 정적 비지역 변수 초기화 과정에서 동적 비지역 초기화가 시작되기 전에 초기화됩니다. 이로 인해 어떤 정적 객체의 생성자에서도 shared_ptr을 안전하게 사용할 수 있습니다.

C++11과 C++14에서는 std:: unique_ptr < T [ ] > 로부터 std:: shared_ptr < T > 를 생성하는 것이 유효합니다:

std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));

shared_ptr std:: default_delete < T [ ] > 객체)를 std::unique_ptr 로부터 획득하므로, 배열이 올바르게 해제됩니다.

이것은 C++17에서 더 이상 허용되지 않습니다. 대신 배열 형식인 std:: shared_ptr < T [ ] > 을 사용해야 합니다.

예제

#include <iostream>
#include <memory>
struct Foo
{
    int id{0};
    Foo(int i = 0) : id{i} { std::cout << "Foo::Foo(" << i <<  ")\n"; }
    ~Foo() { std::cout << "Foo::~Foo(), id=" << id << '\n'; }
};
struct D
{
    void operator()(Foo* p) const
    {
        std::cout << "Call delete from function object. Foo::id=" << p->id << '\n';
        delete p;
    }
};
int main()
{
    {
        std::cout << "1) constructor with no managed object\n";
        std::shared_ptr<Foo> sh1;
    }
    {
        std::cout << "2) constructor with object\n";
        std::shared_ptr<Foo> sh2(new Foo{10});
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::shared_ptr<Foo> sh3(sh2);
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::cout << "sh3.use_count(): " << sh3.use_count() << '\n';
    }
    {
        std::cout << "3) constructor with object and deleter\n";
        std::shared_ptr<Foo> sh4(new Foo{11}, D());
        std::shared_ptr<Foo> sh5(new Foo{12}, [](auto p)
        {
            std::cout << "Call delete from lambda... p->id=" << p->id << '\n';
            delete p;
        });
    }
}

출력:

1) constructor with no managed object
2) constructor with object
Foo::Foo(10)
sh2.use_count(): 1
sh2.use_count(): 2
sh3.use_count(): 2
Foo::~Foo(), id=10
3) constructor with object and deleter
Foo::Foo(11)
Foo::Foo(12)
Call delete from lambda... p->id=12
Foo::~Foo(), id=12
Call delete from function object. Foo::id=11
Foo::~Foo(), id=11

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
LWG 3548 C++11 unique_ptr 로부터의 생성자가 deleter를 복사 생성했음 대신 이동 생성함

참고 항목

새로운 객체를 관리하는 shared_ptr을 생성합니다
(함수 템플릿)
할당자를 사용하여 할당된 새로운 객체를 관리하는 shared_ptr을 생성합니다
(함수 템플릿)
객체가 자신을 참조하는 shared_ptr 을 생성할 수 있도록 합니다
(클래스 템플릿)