728x90

Smart Pointer에서 간단하게 Smart Pointer에 대해서 알아보았다. 이번에는 스마트 포인터의 한 종류인 Unique Pointer (유니크 포인터)에 대해서 공부한다. 

 

 

Unique Pointer (유니크 포인터)

 

유니크 포인터에 대해서 공부하기 전에 유니크 포인터의 Exclusive Ownership이 뭔지 얘기하고 시작한다. 

 

Exclusive Ownership (소유권 독점)

소유권 독점이란 하나의 Object에 단 하나의 Pointer만 가리킬 수 있다는 것이다. 말 그래로 소유권을 독점한다라는 뜻이다. 일반적인 포인터를 사용하게 되면 한 Object당 여러 개의 포인터가 가리킬 수 있는데 Exclusive Ownership은 아니다. 

 

아래

코드는 하나의 객체에 다수의 포인터가 가리킬 경우 생길 수 있는 문제 중 하나이다. 

#include <iostream>
class Cat
{
public:
	Cat() : mAge{ 0 }
	{
		std::cout << "cat constructor" << std::endl;
	}
	~Cat()
	{
		std::cout << "cat destructor" << std::endl;
	}

private:
	int mAge;
};

void memoryDealloc(Cat* dealloc)
{
	delete dealloc;
}

int main()
{
	Cat* choco = new Cat();
	memoryDealloc(choco);
	delete choco;
}

choco객체를 동적으로 선언을 해주고 메모리를 해제해주는 memoeyDealloc함수를 만들어 delete 해준다. 이 과정에서 main함수에서 실수로 또 delete를 해주게 된다면 한 메모리 공간에 대해서 delete를 두 번 해주는 상황이 발생한다. 

 

이러한 문제를 방지하기 위해서 스마트 포인터를 사용하면 된다. 

int main()
{
    std::unique_ptr<Cat> catPtr = std::make_unique<Cat>();
    std::unique_ptr<Cat> catPtr1 = catPtr; //ERROR
}

main함수를 스마트 포인터를 이용하여 다시 고쳐 쓰면 위와 같은데 위 코드에서 스마트 포인터 catPtr과 catPtr1이 선언이 되고 catPtr1는 catPtr이 가리키고 있는 객체의 주소 값을 복사해온다. 하지만 Exclusive Ownership특성 때문에 하나의 객체를 여러 개의 포인터가 가리킬 수 없기 때문에 에러가 난다. 하지만 catPtr1에 해당 객체의 주소 값을 저장하고 싶다면 객체의 소유권을 뺏어오면 된다. 

int main()
{
    std::unique_ptr<Cat> catPtr = std::make_unique<Cat>();
    std::unique_ptr<Cat> catPtr1 = std::move(catPtr);
}

위와 같이 dogPtr을 R-Value로 바꾸고 dogPtr1에 소유권을 이전하면 문제가 생기지 않는다. 

 

스마트 포인터 사용 예

 

Animal Class와 Zoo Class를 추가로 만든다. 그다음 막 개장한 동물원이라서 동물원 안에 동물이 하나밖에 없는 상황이라고 가정을 하면 Zoo Class에 멤버 변수로 Animal 객체 하나만 가지게 된다. 원래 스마트 포인터를 사용하지 않았다면 Rule og Three에 의해서 Destructor, Copy / Move Constructor와 Copy / Move Assignment를 만들어줘야 하지만 스마트 포인터를 이용하면 알아서 scope 단위에서 메모리를 해제해주고 Copy Constructor와 Assignment는 애초에 스마트 포인터가 copy가 안되기 때문에 만들어 주지 않아도 되고 Mov Constructor와 Assignment는 컴파일러가 만들어 주는 함수로 커버가 가능하기 때문에 스마트 포인터를 사용하게 되면 일반 멤버 변수처럼 클래스를 구성해도 무방하다. 

+ Recent posts