Namespaces
Variants

std::unique_ptr<T,Deleter>:: unique_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)
기본 템플릿의 멤버들, unique_ptr<T>
constexpr unique_ptr ( ) noexcept ;
constexpr unique_ptr ( std:: nullptr_t ) noexcept ;
(1)
explicit unique_ptr ( pointer p ) noexcept ;
(2) (C++23부터 constexpr)
unique_ptr ( pointer p, /* 아래 참조 */ d1 ) noexcept ;
(3) (C++23부터 constexpr)
unique_ptr ( pointer p, /* 아래 참조 */ d2 ) noexcept ;
(4) (C++23부터 constexpr)
unique_ptr ( unique_ptr && u ) noexcept ;
(5) (C++23부터 constexpr)
template < class U, class E >
unique_ptr ( unique_ptr < U, E > && u ) noexcept ;
(6) (C++23부터 constexpr)
unique_ptr ( const unique_ptr & ) = delete ;
(7)
template < class U >
unique_ptr ( std:: auto_ptr < U > && u ) noexcept ;
(8) (C++17에서 제거됨)
배열에 대한 특수화 멤버, unique_ptr<T[]>
constexpr unique_ptr ( ) noexcept ;
constexpr unique_ptr ( std:: nullptr_t ) noexcept ;
(1)
template < class U >
explicit unique_ptr ( U p ) noexcept ;
(2) (C++23부터 constexpr)
template < class U >
unique_ptr ( U p, /* 아래 참조 */ d1 ) noexcept ;
(3) (C++23부터 constexpr)
template < class U >
unique_ptr ( U p, /* 아래 참조 */ d2 ) noexcept ;
(4) (C++23부터 constexpr)
unique_ptr ( unique_ptr && u ) noexcept ;
(5) (C++23부터 constexpr)
template < class U, class E >
unique_ptr ( unique_ptr < U, E > && u ) noexcept ;
(6) (C++23부터 constexpr)
unique_ptr ( const unique_ptr & ) = delete ;
(7)
1) 아무것도 소유하지 않는 std::unique_ptr 를 생성합니다. 저장된 포인터와 저장된 삭제자를 값 초기화합니다. Deleter DefaultConstructible 이며 생성 과정에서 예외를 발생시키지 않아야 합니다. 이 오버로드들은 std:: is_default_constructible < Deleter > :: value true 이고 Deleter 가 포인터 타입이 아닌 경우에만 오버로드 해결에 참여합니다.
2) std::unique_ptr 를 생성하며, 이는 p 를 소유합니다. 저장된 포인터를 p 로 초기화하고 저장된 삭제자를 값 초기화합니다. Deleter DefaultConstructible 요구 사항을 만족해야 하며, 생성 과정에서 예외가 발생하지 않아야 합니다. 이 오버로드는 std:: is_default_constructible < Deleter > :: value true 이고 Deleter 가 포인터 타입이 아닌 경우에만 오버로드 해결에 참여합니다.

이 생성자는 클래스 템플릿 인수 추론 에 의해 선택되지 않습니다.

(C++17부터)
3,4) std::unique_ptr 객체를 생성하며, 이 객체는 p 를 소유합니다. 저장된 포인터를 p 로 초기화하고, 삭제자 D 를 아래와 같이 초기화합니다( D 가 참조 타입인지 여부에 따라 다름).
a) 만약 D 가 비-참조 타입 A 인 경우, 시그니처는 다음과 같습니다:
unique_ptr ( pointer p, const A & d ) noexcept ;
(1) ( Deleter 가 nothrow- CopyConstructible 임을 요구함)
unique_ptr ( pointer p, A && d ) noexcept ;
(2) ( Deleter 가 nothrow- MoveConstructible 임을 요구함)
b) 만약 D 가 lvalue-reference 타입 A & 인 경우, 시그니처는 다음과 같습니다:
unique_ptr ( pointer p, A & d ) noexcept ;
(1)
unique_ptr ( pointer p, A && d ) = delete ;
(2)
c) 만약 D 가 lvalue-reference 타입 const A & 인 경우, 시그니처는 다음과 같습니다:
unique_ptr ( pointer p, const A & d ) noexcept ;
(1)
unique_ptr ( pointer p, const A && d ) = delete ;
(2)
모든 경우에 삭제자는 std:: forward < decltype ( d ) < ( d ) 로부터 초기화됩니다. 이러한 오버로드는 std:: is_constructible < D, decltype ( d ) > :: value true 인 경우에만 오버로드 해결에 참여합니다.

이 두 생성자는 클래스 템플릿 인수 추론 에 의해 선택되지 않습니다.

(C++17부터)
2-4) 배열에 대한 특수화에서 포인터 매개변수를 취하는 생성자들은 기본 템플릿과 동일하게 동작하지만, 다음 중 하나가 참인 경우에만 오버로드 해결에 참여하지 않습니다:
  • U pointer 와 동일한 타입인 경우, 또는
  • U std::nullptr_t 인 경우, 또는
  • pointer element_type* 와 동일한 타입이고 U V* 와 같은 포인터 타입이며, V(*)[] element_type(*)[] 로 암시적으로 변환 가능한 경우.
5) unique_ptr 의 소유권을 u 에서 * this 로 이전하여 생성하며, u 에는 널 포인터를 저장합니다. 이 생성자는 std:: is_move_constructible < Deleter > :: value true 인 경우에만 오버로드 해결에 참여합니다. Deleter 가 참조 타입이 아닌 경우, nothrow- MoveConstructible 을 요구합니다 ( Deleter 가 참조인 경우, 이동 생성 후 get_deleter() u.get_deleter() 는 동일한 값을 참조합니다).
6) unique_ptr 를 생성하며, 소유권을 u 에서 * this 로 이전합니다. 여기서 u 는 지정된 삭제자( E )로 생성됩니다. 이 동작은 E 가 참조 타입인지 여부에 따라 다음과 같이 달라집니다:
a) 만약 E 가 참조 타입인 경우, 이 삭제자는 u 의 삭제자로부터 복사 생성됩니다 (이 생성 과정이 예외를 발생시키지 않아야 함).
b) 만약 E 가 비-참조 타입인 경우, 이 deleter는 u 의 deleter로부터 이동 생성됩니다 (이 생성 작업이 예외를 발생시키지 않아야 함).
이 생성자는 다음 조건이 모두 참일 때만 오버로드 해결에 참여합니다:
a) unique_ptr < U, E > :: pointer 는 암시적으로 pointer 로 변환 가능합니다,
b) U는 배열 타입이 아닙니다,
c) Deleter 가 참조 타입이고 E Deleter 와 동일한 타입이거나, Deleter 가 참조 타입이 아니고 E Deleter 로 암시적으로 변환 가능한 경우.
6) 배열에 대한 특수화는 기본 템플릿과 동일하게 동작하지만, 다음의 모든 조건이 참일 때만 오버로드 해결에 참여합니다:
  • U 가 배열 타입인 경우,
  • pointer element_type* 와 동일한 타입인 경우,
  • unique_ptr < U,E > :: pointer unique_ptr < U,E > :: element_type * 와 동일한 타입인 경우,
  • unique_ptr < U,E > :: element_type ( * ) [ ] element_type(*)[] 로 변환 가능한 경우,
  • Deleter 가 참조 타입이고 E Deleter 와 동일한 타입이거나, 또는 Deleter 가 참조 타입이 아니고 E Deleter 로 암시적으로 변환 가능한 경우.
7) 복사 생성자가 명시적으로 삭제되었습니다.
8) 저장된 포인터가 u.release() 로 초기화되고 저장된 삭제자가 값 초기화된 unique_ptr 을 생성합니다. 이 생성자는 U* T* 로 암시적으로 변환 가능하고 Deleter std:: default_delete < T > 와 동일한 타입일 때만 오버로드 해결에 참여합니다.

목차

매개변수

p - 관리할 객체에 대한 포인터
d1, d2 - 객체를 파괴하는 데 사용할 삭제자
u - 소유권을 획득할 다른 스마트 포인터

참고 사항

new와 함께 (2) 오버로드를 사용하는 대신, std::make_unique<T> 를 사용하는 것이 종종 더 나은 방법입니다.

(since C++14)

std:: unique_ptr < Derived > 는 오버로드 (6) 를 통해 std:: unique_ptr < Base > 로 암시적으로 변환 가능합니다 (관리되는 포인터와 std::default_delete 모두 암시적으로 변환 가능하기 때문입니다).

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

배열 형태와 비배열 형태의 new 에서 얻은 포인터를 구분할 수 없기 때문에 포인터 타입으로부터 클래스 템플릿 인수 추론 이 존재하지 않습니다.

(C++17부터)

예제

#include <iostream>
#include <memory>
struct Foo // 관리할 객체
{
    Foo() { std::cout << "Foo 생성자\n"; }
    Foo(const Foo&) { std::cout << "Foo 복사 생성자\n"; }
    Foo(Foo&&) { std::cout << "Foo 이동 생성자\n"; }
    ~Foo() { std::cout << "~Foo 소멸자\n"; }
};
struct D // deleter
{
    D() {};
    D(const D&) { std::cout << "D 복사 생성자\n"; }
    D(D&) { std::cout << "D 비상수 복사 생성자\n"; }
    D(D&&) { std::cout << "D 이동 생성자 \n"; }
    void operator()(Foo* p) const
    {
        std::cout << "D가 Foo를 삭제 중입니다\n";
        delete p;
    };
};
int main()
{
    std::cout << "예제 생성자(1)...\n";
    std::unique_ptr<Foo> up1; // up1이 비어 있음
    std::unique_ptr<Foo> up1b(nullptr); // up1b is empty
    std::cout << "예시 생성자(2)...\n";
    {
        std::unique_ptr<Foo> up2(new Foo); //up2가 Foo를 소유함
    } // Foo 삭제됨
    std::cout << "예시 생성자(3)...\n";
    D d;
    {   // deleter 타입은 참조가 아님
        std::unique_ptr<Foo, D> up3(new Foo, d); // deleter 복사됨
    }
    {   // deleter 타입은 참조형입니다
        std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b는 d에 대한 참조를 보유합니다
    }
    std::cout << "예제 생성자(4)...\n";
    {   // deleter는 참조가 아님
        std::unique_ptr<Foo, D> up4(new Foo, D()); // deleter moved
    }
    std::cout << "Example constructor(5)...\n";
    {
        std::unique_ptr<Foo> up5a(new Foo);
        std::unique_ptr<Foo> up5b(std::move(up5a)); // 소유권 이전
    }
    std::cout << "예시 생성자(6)...\n";
    {
        std::unique_ptr<Foo, D> up6a(new Foo, d); // D가 복사됨
        std::unique_ptr<Foo, D> up6b(std::move(up6a)); // D가 이동됨
        std::unique_ptr<Foo, D&> up6c(new Foo, d); // D는 참조입니다
        std::unique_ptr<Foo, D> up6d(std::move(up6c)); // D가 복사됨
    }
#if (__cplusplus < 201703L)
    std::cout << "예제 생성자(7)...\n";
    {
        std::auto_ptr<Foo> up7a(new Foo);
        std::unique_ptr<Foo> up7b(std::move(up7a)); // 소유권 이전
    }
#endif
    std::cout << "예시 배열 생성자...\n";
    {
        std::unique_ptr<Foo[]> up(new Foo[3]);
    } // 세 개의 Foo 객체 삭제됨
}

출력:

예시 생성자(1)...
예시 생성자(2)...
Foo ctor
~Foo dtor
예시 생성자(3)...
Foo ctor
D 복사 생성자
D가 Foo를 삭제 중
~Foo dtor
Foo ctor
D가 Foo를 삭제 중
~Foo dtor
예시 생성자(4)...
Foo ctor
D 이동 생성자
D가 Foo를 삭제 중
~Foo dtor
예시 생성자(5)...
Foo ctor
~Foo dtor
예시 생성자(6)...
Foo ctor
D 복사 생성자
D 이동 생성자
Foo ctor
D 비상수 복사 생성자
D가 Foo를 삭제 중
~Foo dtor
D가 Foo를 삭제 중
~Foo dtor
예시 생성자(7)...
Foo ctor
~Foo dtor
예시 배열 생성자...
Foo ctor
Foo ctor
Foo ctor
~Foo dtor
~Foo dtor
~Foo dtor

결함 보고서

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

DR 적용 대상 게시된 동작 올바른 동작
LWG 2118 C++11 unique_ptr<T[]> 의 생성자들이 한정 변환(qualification conversions)을 거부했습니다. 수용.
LWG 2520 C++11 unique_ptr<T[]> 가 실수로 nullptr_t 로부터 생성 불가능하게 되었습니다. 생성 가능하게 변경.
LWG 2801 C++11 기본 생성자가 제약되지 않았습니다. 제약됨.
LWG 2899 C++11 이동 생성자가 제약되지 않았습니다. 제약됨.
LWG 2905 C++11 포인터와 삭제자로부터의 생성자에 대한 제약이 잘못되었습니다. 수정됨.
LWG 2944 C++11 일부 사전 조건들이 LWG 2905에 의해 실수로 제거되었습니다. 복원됨.