Smart pointer

headkio·2020년 9월 19일
0

C++

목록 보기
28/35
post-thumbnail

종류

unique_ptr <- 중요, 강추
shared_ptr <- 잘안씀
weak_ptr <- 잘안씀

기존 포인터 문제

메모리 해제를 수동으로 해주어야 한다.
스마트 포인터는 delete를 직접할 필요가 없다.
가비지 콜렉터보다 빠르다.
주기적으로 가비지를 콜렉터하는게 아니라 필요하지 않는 순간에 메모리를 해제해 준다.

unique_ptr

소유자가 하나(unique) 밖에 없는 포인터이다.

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

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

범위를 벗어날 때 delete 된다.
myVector의 소멸자가 호출되며 안의 new Vector도 따로 지워줄 필요가 없다.
복사, 대입 불가.

std::unique_ptr<Vector> myVector(new Vector(10.f, 30.f));
std::unique_ptr<Vector> copiedVector1 = myVector; // ERROR !!
std::unique_ptr<Vector> copiedVector2(myVector); // ERROR !!

unique_ptr 적절한 사용 예

  1. 생성자에서 사용
class Player
{
  private:
    std::unique_ptr<Vector> mLocation;
}

class가 사라질때 자동으로 메모리 해제되므로 소멸자를 써줄 필요 없다.

  1. 지역 변수에서 new를 사용할 경우
  2. STL 벡터에 포인터 저장할 때
std::vector<std::unique_ptr<Player>> playerList;

playerList.push_back(std::unique_ptr<Player>(new Player("LuLu")));
playerList.push_back(std::unique_ptr<Player>(new Player("Coco")));
// playerList.clear(); // clear도 할 필요 없다.

unique_ptr 잘못된 사용

Vector* vectorPtr = new Vector(10.f, 30.f);

std::unique_ptr<Vector> vector1(vectorPtr);
std::unique_ptr<Vector> vector2(vectorPtr);
vector1 = nullptr;
  1. vector1이 지워질때 소멸자가 vectorPtr를 지운다.
  2. vector2는 지워진 vectorPtr의 주소를 가지고 있다.
  3. vector2가 사라질때 이미 지워진 주소를 지우려고 시도..... (Boom!)

해결책

std::unique_ptr<Vector> myVector = std::make_unique<Vector>(10.f, 30.f);

Vector* vectorPtr = new Vector(10.f, 30.f);
std::unique_ptr<Vector> myVector = std::make_unique(vectorPtr); // Error !
std::unique_ptr<Vector> myVector = std::make_unique<Vector>(vectorPtr); // Error !
std::unique_ptr<Vector> myVector = std::make_unique<Vector*>(10.f, 30.f); // Error !

unique_ptr를 쓸때는 make_unique를 꼭 쓰자!

reset()

unique_ptr 재설정 하기
재설정될 때 소유하고 있던 포인터는 소멸시킨다.

std::unique_ptr<Vector> myVector = std::make_unique<Vector>(10.f, 30.f);
vector.reset(new Vector(20.f, 40.f));
vector.reset(); // vector = nullptr 과 같다.

get()

unique_ptr 가 가지고 있던 원시 포인터를 반환한다.
반환된 포인터를 따로 지우지 말자!

release()

unique_ptr 가 가지고 있던 원시 포인터의 소유권을 넘겨준다.
언제 해제될지 헷갈리기 시작함. 잘 쓰지말자.

move()

소유권 이전이 필요하다면 move()를 사용하자

unique_ptr<Vector> vector2(std::move(vector1));

vector1에 있는 모든 포인터를 vector2에 대입하고
vector1에는 nullptr를 넣는다.

shared_ptr

참조 카운팅 기반 동작.
몇번 참조됐는지를 카운팅하고 카운팅이 0이 됐을 때 소멸된다.

std:shared_ptr<Vector> vector = std::make_shared<Vector>(10.f, 30.f);
std:shared_ptr<Vector> vector2 = vector;

weak_ptr

약한(Weak) 참조.
약한 참조는 원시 포인터 해제에 영향을 끼치지 않는다.
약한 참조로 참조되는 객체는 강한 참조의 객체가 0이 되면 소멸됨.

std::shared_ptr<Person> owner = std::make_shared<Person>("Pope");
std::weak_ptr<Person> weakOwner = owner;
profile
돌아서서 잊지말고, 잘 적어 놓자

0개의 댓글