SW/C++

C++ : unique_ptr : 유니크 포인터 개념, 필요성, 장점, 활용법

얇은생각 2020. 5. 4. 07:30
반응형

C++ : unique_ptr : 유니크 포인터 개념, 필요성, 장점, 활용법

 

스마트 포인터

- unique_ptr
- shared_ptr
- weak_ptr

 

 

예시: 포인터

#include "Vector.h"

int main ()
{
  Vector* myVector = new Vector(10.f, 30.f);
 
  //
  
  delete myVector;
  
  return 0;
}

 

항상 포인터를 생성하는 순간, delete를 구현해주어야 합니다. 하지만 프로그래머들이 가끔 실수를 할 수 있습니다. 

더 이상 포인터가 필요하지 않을 때 메모리를 해제해야 합니다. 스마트 포인터를 쓰면 delete를 직접 호출할 필요가 없습니다. 그리고 가비지 컬렉션보다 빨라집니다. 

 

 

 

unique_ptr

#include <memory>
#include "Vector.h"

int main()
{
  std::unique_ptr<Vector> myVector(new Vector(10.f, 30.f);
  myVector->Print();
  
  return 0;
}

 

포인터를 단독으로 소유합니다. 원시 포인터는 누구하고도 공유되지 않습니다. 따라서 복사나 대입이 불가합니다. unique_ptr가 범위를 벗어날 때, 원시포인터는 지워집니다. 

과연 언제 unique_ptr을 사용하는게 좋을까요? 바로 클래스 멤버 변수로 활용할 때 좋습니다. 소멸자가 호출되면 알아서 해제되기 때문입니다.

두번째로, 지역 변수로 활용할 때 좋습니다. 개발자의 실수를 줄여줄 수 있습니다. 

세번째로, STL 벡터에 포인터를 저장할 때 좋습니다. 기존에는 직접 하나하나 포인터를 지워주어야 했지만, 벡터를 clear 하면, unique_ptr은 자동적으로 포인터를 지워줍니다. 

 

 

 

원시 포인터 공유

Vecotr * vectorPtr = new Vector(10.f, 30.f);
std::unique_ptr<Vector> vector(vectorPtr);
std::unique_ptr<Vector> anotherVector(vectorPtr);
anotherVector = nullptr;

 

기존에는 이렇게 unique_ptr의 포인터를 공유할 수 있었습니다. 이런 경우, unique_ptr의 개념이 깨지게 되며, 오류의 여지가 생길 수 있습니다. 

 

 

#include <memory>
#include "Vector.h"

int main()
{
  std::unique_ptr<Vector> myVector = std::make_unique<Vector>(10.f, 30.f);
  
  myVector->Print();
  
  return 0;
}

 

그러나 이렇게 make_unique를 활용하면 위 문제를 해결할 수 있습니다. 이 기능은 C++14부터 지원되었습니다. 주어진 매개변수와 자료형으로 new 키워드를 호출해 줍니다. 따라서 원시 포인터와 같습니다. 둘 이상의 std::unique_ptr가 원시 포인터를 공유할 수 없도록 막는게 전부입니다. 

 

 

// C++11 (C++14를 쓸 수 없는 경우)
std::unique_ptr<Vector> vector(new Vector(10.f, 30.f));
std::unique_ptr<Vector[]> vectors(new Vector[20]);

// C++14
std::unique_ptr<Vector> vector = std::make_unique<Vector>(10.f, 30.f);
std::unique_ptr<Vector[]> vectors = std::make_unique<Vector[]>(20);

 

따라서 위와 같은 방법으로 유니크 포인터를 만들 수 있습니다.  다음 포스팅에서는 유니크 포인터 재설정, 원피 포인터 가져오기, 소유권 박탈하기, 소유권 이전하기, 베스트 프랙티스 등등에 대해 알아보겠습니다.

반응형