C++ unique_ptr

2021. 3. 24. 10:47·C++/Library

unique_ptr

unique_ptr

  • <memory> 라이브러리

  • scope를 벗어나면 자동으로 메모리를 해제하므로 메모리 누수를 방지할 수 있다.


예제

main.cpp

  #include <iostream>
  #include <memory>
  #include "Resource.h"

  using namespace std;

  int            main()
  {
    std::unique_ptr<Resource> res(new Resource(100000000));
  }
  /* stdout
  Resource length constructed
  Resource destoryed
  */

Resource.h

  #pragma once

  #include <iostream>

  class Resource
  {
  public:
    int    *data_ = nullptr;
    unsigned length_ = 0;

    Resource()
    {
      std::cout << "Resource default constructed\n";
    }

    Resource(unsigned length)
    {
      std::cout << "Resource length constructed\n";
      init(length);
    }

    Resource(const Resource& res)
    {
      std::cout << "Resource copy constructed\n";
      init(res.length_);
      for (unsigned i = 0; i < length_; ++i)
        data_[i] = res.data_[i];
    }

    ~Resource()
    {
      std::cout << "Resource destoryed\n";

      if (data_ != nullptr) delete[] data_;
    }

    void    init(unsigned length)
    {
      data_ = new int[length];
      length_ = length;
    }

    Resource& operator = (Resource& res)
    {
      std::cout << "Resource copy assignment\n";
      if (&res == this) return *this;

      if (data_ != nullptr) delete[] data_;
      init(res.length_);
      for (unsigned i = 0; i < length_; ++i)
        data_[i] = res.data_[i];
      return *this;
    }

    void    print()
    {
      for (unsigned i = 0; i < length_; ++i)
        std::cout << data_[i] << ' ';
      std::cout << std::endl;
    }

    void    setAll(const int& v)
    {
      for (unsigned i = 0; i < length_; ++i)
        data_[i] = v;
    }
  };

make_unique

  • unique_ptr를 안전하게 반환하는 함수

    main.cpp

    #include <iostream>
    #include <memory>
    #include "Resource.h"
    
    using namespace std;
    
    auto        doSomething()
    {
      //return std::unique_ptr<Resource>(new Resource(5));
      return std::make_unique<Resource>(5); // 이걸 더 추천
    }
    
    int            main()
    {
      auto res1 = doSomething();
    
      res1->setAll(5);
    
      std::unique_ptr<Resource> res2;
    
      if (res1 != nullptr)
      {
        cout << "res1 : ";
        res1->print();
      }
      if (res2 != nullptr)
      {
        cout << "res2 : ";
        res2->print();
      }
    
      cout << boolalpha;
      cout << "res1 : " << static_cast<bool>(res1) << endl;
      cout << "res2 : " << static_cast<bool>(res2) << endl;
      cout << '\n';
    
      res2 = std::move(res1);
    
      if (res1 != nullptr) 
      {
        cout << "res1 : ";
        res1->print();
      }
      if (res2 != nullptr) 
      {
        cout << "res2 : ";
        res2->print();
      }
    
      cout << "res1 : " << static_cast<bool>(res1) << endl;
      cout << "res2 : " << static_cast<bool>(res2) << endl;
    }
    
    /* stdout stderr
    Resource length constructed
    res1 : 5 5 5 5 5
    res1 : true
    res2 : false
    
    res2 : 5 5 5 5 5
    res1 : false
    res2 : true
    Resource destoryed
    */
    • 아래의 명령은 에러가 발생한다.

      main.cpp

      res2 = res1;
      error C2280: 'std::unique_ptr<Resource,std::default_delete<Resource>> &std::unique_ptr<Resource,std::default_delete<Resource>>::operator =(const std::unique_ptr<Resource,std::default_delete<Resource>> &)': attempting to reference a deleted function
      • unique_ptr는 말 그대로 포인터를 단독 사용하기 위해 쓰는 클래스이므로, 라이브러리 자체에서 복사 대입(copy assignment, operator =)을 delete한 것이다.

copy constructor도 delete한 상태임을 보여주는 예제

main.cpp

  #include <iostream>
  #include <memory>
  #include "Resource.h"

  using namespace std;

  auto        doSomething(std::unique_ptr<Resource> res)  // 에러
  {
    res->setAll(10);
  }

  int            main()
  {
    auto res1 = std::make_unique<Resource>(5);
    res1->setAll(1);
    res1->print();

    doSomething(res1);

    res1->print();
  }
  error C2280: 'std::unique_ptr<Resource,std::default_delete<Resource>>::unique_ptr(const std::unique_ptr<Resource,std::default_delete<Resource>> &)': attempting to reference a deleted function
  • 에러 메시지를 통해 라이브러리에서 복사 생성자(copy constructor)를 delete한 것임을 알 수 있다.
  • 이 예제에서 doSomething(std::move(res1)) 과 같이 R-value로 넘기면, doSomething 함수 내부로 unique_ptr인 res1이 옮겨간다.

    • 해당 함수의 scope 밖으로 나오는 순간(함수가 끝나고 스택이 되감길 때) unique_ptr의 특성으로 res가 사라진다.

    • 글로 설명하는 것보다 예제를 보는게 쉽다.

    main.cpp

    #include <iostream>
    #include <memory>
    #include "Resource.h"
    
    using namespace std;
    
    auto        doSomething(std::unique_ptr<Resource> res)
    {
      res->setAll(10);
    }
    
    int            main()
    {
      auto res1 = std::make_unique<Resource>(5);
      res1->setAll(1);
      res1->print();
    
      cout << boolalpha << static_cast<bool>(res1) << endl;
    
      doSomething(std::move(res1));
    
      cout << static_cast<bool>(res1) << endl;
    }
    
    /* stdout stderr
    Resource length constructed
    1 1 1 1 1
    true
    Resource destoryed
    false
    */

get()

  • unique_ptr로 가지고 있는 포인터를 반환한다.

<memory>

// STRUCT TEMPLATE _Get_deleter_pointer_type
template <class _Ty, class _Dx_noref, class = void>
struct _Get_deleter_pointer_type { // provide fallback
    using type = _Ty*;
};

...

template <class _Ty, class _Dx /* = default_delete<_Ty> */>
class unique_ptr {
public:
  using pointer      = typename _Get_deleter_pointer_type<_Ty, remove_reference_t<_Dx>>::type;

...

_NODISCARD pointer get() const noexcept {
    return _Mypair._Myval2;
}

...

private:
  template <class, class>
  friend class unique_ptr;

  _Compressed_pair<_Dx, pointer> _Mypair;
};

<xmemory>

template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>
class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first
public:
    _Ty2 _Myval2;

...
};
저작자표시 (새창열림)

'C++ > Library' 카테고리의 다른 글

C++ weak_ptr  (0) 2021.03.24
C++ shared_ptr  (0) 2021.03.24
C++ std::move  (0) 2021.03.24
C++ 출력 스트림 끊기  (0) 2021.03.24
C++ std::exception  (0) 2021.03.22
'C++/Library' 카테고리의 다른 글
  • C++ weak_ptr
  • C++ shared_ptr
  • C++ std::move
  • C++ 출력 스트림 끊기
Caniro
Caniro
  • Caniro
    Minimalism
    Caniro
  • 전체
    오늘
    어제
    • 분류 전체보기 (317)
      • Algorithm (13)
        • 알기 쉬운 알고리즘 (10)
        • Search (1)
        • Sort (2)
      • Arduino (0)
      • C++ (185)
        • Class (46)
        • Exception (6)
        • Library (51)
        • Overloading (10)
        • SmartPointer (5)
        • Syntax (33)
        • TBC++ (23)
        • Templates (9)
        • VisualStudio (2)
      • Embedded (1)
      • Git (4)
      • Java (5)
      • Linux (16)
        • Error (1)
        • Linux Structure (11)
      • MacOS (7)
      • OS (1)
        • Concurrency (1)
      • Python (21)
        • Class (1)
        • Function (2)
        • Syntax (17)
      • Raspberrypi (9)
      • Review (1)
      • Utility (12)
        • VSCode (5)
        • VirtualBox (3)
      • Web (8)
        • Nginx (1)
        • React (3)
        • Django (1)
      • Windows (20)
        • Registry (3)
        • WSL (1)
        • DeviceDriver (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    vscode
    java
    맥북 카카오톡 알림 안뜸
    스프링 프레임워크 핵심 기술
    citrix workspace
    백기선
    Windows 11
    윈도우
    로지텍 마우스 제스처
    제외
    그림판
    unix
    스프링
    시스템 복구
    윈도우 명령어
    알림
    SunOS 5.1
    spring
    Workspace
    mspaint
    Solaris 10
    KakaoTalk
    dism
    SFC
    MacOS
    logi options
    EXCLUDE
    windows
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Caniro
C++ unique_ptr
상단으로

티스토리툴바