C++ unique_ptr

2021. 3. 24. 10:47·SW개발/C++
반응형

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;

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

'SW개발 > C++' 카테고리의 다른 글

C++ weak_ptr  (0) 2021.03.24
C++ shared_ptr  (0) 2021.03.24
C++ std::move  (0) 2021.03.24
C++ 이동 생성자와 이동 대입 (Move Constructor and Move Assignment)  (0) 2021.03.24
C++ 출력 스트림 끊기  (0) 2021.03.24
'SW개발/C++' 카테고리의 다른 글
  • C++ weak_ptr
  • C++ shared_ptr
  • C++ std::move
  • C++ 이동 생성자와 이동 대입 (Move Constructor and Move Assignment)
Caniro
Caniro
  • Caniro
    Minimalism
    Caniro
  • 전체
    오늘
    어제
    • 전체보기 (319)
      • SW개발 (268)
        • Java Spring (6)
        • C++ (186)
        • Python (21)
        • Linux (16)
        • 알고리즘 (13)
        • Git (4)
        • Embedded (1)
        • Raspberrypi (9)
        • React (3)
        • Web (2)
        • Windows Device Driver (6)
      • IT(개발아님) (46)
        • Windows (26)
        • MacOS (7)
        • Utility (11)
      • 챗봇 짬통 (0)
      • 일상 (2)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

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

티스토리툴바