Namespaces
Variants

std:: 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)
헤더 파일에 정의됨 <memory>
template <

class T,
class Deleter = std:: default_delete < T >

> class unique_ptr ;
(1) (C++11부터)
template <

class T,
class Deleter

> class unique_ptr < T [ ] , Deleter > ;
(2) (C++11부터)

std::unique_ptr 는 다른 객체를 포인터를 통해 소유하고 관리하는 스마트 포인터이며, unique_ptr 이 스코프를 벗어날 때 해당 객체를 자동으로 처리합니다.

객체는 다음 중 하나가 발생할 때 연관된 삭제자를 사용하여 폐기됩니다:

  • 관리 중인 unique_ptr 객체가 소멸될 때.
  • 관리 중인 unique_ptr 객체가 operator= 또는 reset() 을 통해 다른 포인터를 할당받을 때.

객체는 사용자가 제공한 삭제자를 사용하여 get_deleter ( ) ( ptr ) 를 호출하여 처리됩니다. 기본 삭제자( std::default_delete )는 delete 연산자를 사용하며, 이는 객체를 파괴하고 메모리를 해제합니다.

A unique_ptr 는 객체를 소유하지 않을 수도 있으며, 이 경우 empty 로 설명됩니다.

unique_ptr 에는 두 가지 버전이 있습니다:

  1. 단일 객체를 관리합니다 (예: new 로 할당된 객체).
  2. 객체의 동적 할당 배열을 관리합니다 (예: new [ ] 로 할당된 배열).

이 클래스는 MoveConstructible MoveAssignable 요구사항을 만족하지만, CopyConstructible CopyAssignable 요구사항은 만족하지 않습니다.

만약 T* 가 유효한 타입이 아닌 경우(예: T 가 참조 타입인 경우), std :: unique_ptr < T, Deleter > 의 정의를 인스턴스화하는 프로그램은 형식에 맞지 않습니다.

타입 요구사항
-
Deleter FunctionObject 이거나 FunctionObject 에 대한 좌측값 참조이거나 함수에 대한 좌측값 참조여야 하며, unique_ptr < T, Deleter > :: pointer 타입의 인수로 호출 가능해야 합니다.

목차

참고 사항

오직 비-상수 unique_ptr 만이 관리 객체의 소유권을 다른 unique_ptr 로 이전할 수 있습니다. 객체의 수명이 const std :: unique_ptr 에 의해 관리되는 경우, 해당 객체의 수명은 포인터가 생성된 범위로 제한됩니다.

unique_ptr 는 일반적으로 다음과 같은 객체의 수명을 관리하는 데 사용됩니다:

  • 동적 수명을 가진 객체를 처리하는 클래스와 함수에 예외 안전성을 제공하며, 정상 종료 시와 예외를 통한 종료 시 모두 삭제를 보장합니다.
  • 동적 수명을 가진 유일하게 소유된 객체의 소유권을 함수로 전달하기.
  • 동적 수명을 가진 고유 소유 객체를 함수로부터 획득하기.
  • 이동 인식 컨테이너(예: 다형적 동작이 필요한 경우 동적으로 할당된 객체에 대한 포인터를 보유하는 std::vector 와 같은 컨테이너)에서 요소 타입으로 사용됩니다.

unique_ptr 불완전한 타입 T 에 대해 생성될 수 있으며, 이는 pImpl 관용구 에서 핸들로 사용하기 용이하게 합니다. 기본 삭제자를 사용하는 경우, T 는 삭제자가 호출되는 코드 지점에서 완전한 타입이어야 합니다. 이는 unique_ptr 의 소멸자, 이동 할당 연산자, 그리고 reset 멤버 함수에서 발생합니다. (대조적으로, std::shared_ptr 는 불완전한 타입에 대한 원시 포인터로부터 생성될 수 없지만, T 가 불완전한 상태에서 소멸될 수 있습니다). T 가 클래스 템플릿 특수화인 경우, unique_ptr 를 피연산자로 사용하는 것(예: ! p )은 ADL 로 인해 T 의 매개변수가 완전한 타입이어야 함을 유의하십시오.

만약 T 가 어떤 기본 클래스 B 파생 클래스 라면, unique_ptr < T > unique_ptr < B > 암시적으로 변환 가능 합니다. 결과로 생성된 unique_ptr < B > 의 기본 삭제자는 B 에 대한 operator delete 를 사용하므로, B 의 소멸자가 가상 이 아닌 경우 정의되지 않은 동작 을 초래합니다. std::shared_ptr 은 다르게 동작한다는 점에 유의하세요: std:: shared_ptr < B > T 타입에 대한 operator delete 를 사용하며, B 의 소멸자가 가상 이 아니더라도 소유된 객체가 올바르게 삭제됩니다.

std::shared_ptr 와 달리, unique_ptr NullablePointer 를 만족하는 임의의 커스텀 핸들 타입을 통해 객체를 관리할 수 있습니다. 이는 예를 들어, typedef boost::offset_ptr pointer; 를 정의하는 Deleter 를 제공하여 공유 메모리에 위치한 객체를 관리할 수 있게 합니다. 또는 다른 fancy pointer 를 사용할 수도 있습니다.

기능 테스트 매크로 표준 기능
__cpp_lib_constexpr_memory 202202L (C++23) constexpr std::unique_ptr

중첩 타입

유형 정의
pointer std:: remove_reference < Deleter > :: type :: pointer 해당 유형이 존재하는 경우, 그렇지 않으면 T* . NullablePointer 요구 사항을 충족해야 함
element_type T , 이 unique_ptr 가 관리하는 객체의 유형
deleter_type Deleter , 함수 객체 또는 함수나 함수 객체에 대한 lvalue 참조로, 소멸자에서 호출됨

멤버 함수

새로운 unique_ptr 을 생성합니다
(public member function)
관리 객체가 존재할 경우 파괴합니다
(public member function)
unique_ptr 를 할당합니다
(public member function)
Modifiers
관리 객체에 대한 포인터를 반환하고 소유권을 해제합니다
(public member function)
관리 객체를 교체합니다
(public member function)
관리 객체들을 교환합니다
(public member function)
Observers
관리 객체에 대한 포인터를 반환합니다
(public member function)
관리 객체 파괴에 사용되는 삭제자를 반환합니다
(public member function)
연관된 관리 객체가 있는지 확인합니다
(public member function)
Single-object version, unique_ptr<T>
관리 객체에 대한 포인터를 역참조합니다
(public member function)
Array version, unique_ptr<T[]>
관리 배열에 대한 인덱스 접근을 제공합니다
(public member function)

비멤버 함수

새로운 객체를 관리하는 unique pointer를 생성합니다
(함수 템플릿)
다른 unique_ptr 또는 nullptr 와 비교합니다
(함수 템플릿)
관리되는 포인터의 값을 출력 스트림에 출력합니다
(함수 템플릿)
std::swap 알고리즘을 특수화합니다
(함수 템플릿)

헬퍼 클래스

std::unique_ptr 에 대한 해시 지원
(클래스 템플릿 특수화)

예제

#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <locale>
#include <memory>
#include <stdexcept>
// 아래 런타임 다형성 데모를 위한 헬퍼 클래스
struct B
{
    virtual ~B() = default;
    virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B
{
    D() { std::cout << "D::D\n"; }
    ~D() { std::cout << "D::~D\n"; }
    void bar() override { std::cout << "D::bar\n"; }
};
// unique_ptr를 소비하는 함수는 값으로 받거나 rvalue 참조로 받을 수 있습니다
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}
// 아래 커스텀 삭제자 데모를 위한 헬퍼 함수
void close_file(std::FILE* fp)
{
    std::fclose(fp);
}
// unique_ptr 기반 연결 리스트 데모
struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
    std::unique_ptr<Node> head;
    ~List()
    {
        // 리스트 노드를 루프에서 순차적으로 파괴, 기본 소멸자
        // 재귀적으로 자신의 "next"의 소멸자를 호출했을 것입니다.
        // 충분히 큰 리스트에 대해 스택 오버플로우를 발생시킵니다.
        while (head)
        {
            auto next = std::move(head->next);
            head = std::move(next);
        }
    }
    void push(int data)
    {
        head = std::unique_ptr<Node>(new Node{data, std::move(head)});
    }
};
int main()
{
    std::cout << "1) 고유 소유권 의미론 데모\n";
    {
        // (고유 소유권을 가진) 리소스 생성
        std::unique_ptr<D> p = std::make_unique<D>();
        // 소유권을 "pass_through"로 이전합니다,
        // 이는 반환값을 통해 소유권을 다시 전달함
        std::unique_ptr<D> q = pass_through(std::move(p));
        // "p"는 이제 이동된 이후의 '빈' 상태이며, nullptr과 같습니다
        assert(!p);
    }
    std::cout << "\n" "2) 런타임 다형성 데모\n";
    {
        // 파생 리소스를 생성하고 기본 타입을 통해 이를 가리킵니다
        std::unique_ptr<B> p = std::make_unique<D>();
        // 동적 디스패치는 예상대로 작동합니다
        p->bar();
    }
    std::cout << "\n" "3) 커스텀 삭제자 데모\n";
    std::ofstream("demo.txt") << 'x'; // 파일 읽기 준비
    {
        using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>;
        unique_file_t fp(std::fopen("demo.txt", "r"), &close_file);
        if (fp)
            std::cout << char(std::fgetc(fp.get())) << '\n';
    } // “close_file()”가 여기서 호출됨 (“fp”가 null이 아닌 경우)
    std::cout << "\n" "4) 사용자 정의 람다 표현식 삭제자 및 예외 안전성 데모\n";
    try
    {
        std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
        {
            std::cout << "커스텀 삭제자로부터 파괴 중...\n";
            delete ptr;
        });
        throw std::runtime_error(""); // "p"가 일반 포인터였다면 여기서 메모리 누수가 발생할 것임
    }
    catch (const std::exception&)
    {
        std::cout << "예외 발생\n";
    }
    std::cout << "\n" "5) unique_ptr 배열 형태 데모\n";
    {
        std::unique_ptr<D[]> p(new D[3]);
    } // “D::~D()”는 3번 호출됨
    std::cout << "\n" "6) 연결 리스트 데모\n";
    {
        List wall;
        const int enough{1'000'000};
        for (int beer = 0; beer != enough; ++beer)
            wall.push(beer);
        std::cout.imbue(std::locale("en_US.UTF-8"));
        std::cout << enough << " 벽에 있는 맥주 병...\n";
    } // 모든 맥주를 파괴합니다
}

가능한 출력:

1) 고유 소유권 의미론 데모
D::D
D::bar
D::~D
2) 런타임 다형성 데모
D::D
D::bar
D::~D
3) 사용자 정의 삭제자 데모
x
4) 사용자 정의 람다 표현식 삭제자 및 예외 안전성 데모
D::D
사용자 정의 삭제자에서 파괴 중...
D::~D
예외를 잡았음
5) unique_ptr 배열 형태 데모
D::D
D::D
D::D
D::~D
D::~D
D::~D
6) 연결 리스트 데모
1,000,000 병의 맥주가 벽에...

결함 보고서

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

DR 적용 대상 게시된 동작 올바른 동작
LWG 4144 C++11 T* 가 유효한 타입을 형성해야 할 필요가 없었음 필요함

참고 항목

(C++11)
공유 객체 소유권 의미론을 가진 스마트 포인터
(클래스 템플릿)
(C++11)
std::shared_ptr 이 관리하는 객체에 대한 약한 참조
(클래스 템플릿)
(C++26)
값 의미론을 가진 동적으로 할당된 객체를 포함하는 래퍼
(클래스 템플릿)
(C++17)
CopyConstructible 타입의 인스턴스를 보유하는 객체
(클래스)