유니크 포인터 unique_ptr
스마트 포인터란?
* 유니크 포인터는 스마트 포인터의 한 종류이다.
* 스마트 포인터란 포인터처럼 동작하는 클래스 템플릿이다.
* 스마트 포인터는
unipue_ptr, shared_ptr, weak_ptr 등이 있다.
기존의 포인터
Dog* dog = new Dog(10, "까망이");
delete dog;
* C++에서 new 연산자를 통해 heap 영역에 생성된 객체는 포인터를 가지고 접근해야 한다.
객체를 삭제하고 싶으면 포인터를 사용해 직접 메모리를 해제해야 한다.
* 스마트 포인터를 사용하면 직접 delete를 할 필요 없이
알아서 메모리를 해제한다. 메모리 누수가 일어날 확률이 적어지며,
가비지 컬렉션보다 빠르다.
* 스마트 포인터와 비교하기 위해
기존 포인터를 원시 포인터(raw pointer, naked pointer)라고 부른다.
유니크 포인터란?
* template< class T, class Deleter = std::default_delete<T> > class unique_ptr;
클래스 템플릿인데 포인터의 역할을 수행한다.
포인터처럼 동작하기 위한 연산자 오버로딩이 포함되어 있다.
* 유니크 포인터는 포인터가 단 하나라는 의미이다.
포인터가 유일하므로 메모리를 해제하는 책임자가 명확하다.
* 유일하기 때문에 복사, 대입이 불가능하다. (컴파일 에러)
원시 포인터를 공유하지 않는다.
* unique_ptr가 범위를 벗어나면 원시 포인터가 가리키는 메모리가 자동으로 해제된다.
unique_ptr도 객체이기 때문에 소멸자를 가지고 있고,
이 소멸자가 원시 포인터가 가리키는 메모리를 해제하는 방식이다.
* unique_ptr가 stack에 생성된 객체라면 범위만 벗어나도 소멸자가 호출되고,
heap에 생성된 객체라면 delete를 해야 소멸자가 호출되어
원시 포인터가 가리키는 메모리를 해제한다.
예시 (C++11 기준)
#include <memory>
class Dog :public Animal {
public:
~Dog() { cout << "Dog 소멸자 호출됨" << endl; }
void speak() { cout << "멍멍" << endl; }
};
int main() {
unique_ptr<Dog> dog(new Dog(10, "까망이"));
dog->speak();
return 0;
}
* include <memory>를 해야 사용할 수 있다.
* dog->speak(); 를 보면
객체를 마치 포인터처럼 사용한다. (연산자 오버로딩)
* 유니크 포인터 객체가 범위를 벗어나 소멸자가 호출되고,
Dog 객체를 delete 한다.
원시 포인터가 가리키는 객체 삭제 기준
* 유니크 포인터 안에 있는 삭제자를 사용해
원시 포인터가 가리키는 객체를 삭제하는 기준이 있다.
1. 유니크 포인터가 삭제될 때.
2. 연산자=나 reset()을 사용해 다른 포인터가 할당될 때.
* 연산자=로 nullptr를 넣거나 reset() 함수에 매개변수가 없다면
원시 포인터가 null이 되고, 가리키는 객체를 delete 한다.
C++11에서의 문제
int main() {
Dog* ptr = new Dog(10, "까망이");
unique_ptr<Dog> dog1(ptr);
unique_ptr<Dog> dog2(ptr);
return 0;
}
* 유니크 포인터는 전제가
(나만이 유일하게 소유하는 중)인데,
매개변수로 객체 포인터가 들어간다.
* 같은 포인터에 유니크 포인터 객체가 여러 개 생겨서
이미 해제된 메모리 주소를 다시 해제하는 일이 생겼고,
에러가 났다.
* 즉, 밖에서 객체를 생성하고 유니크 포인터에 나중에 넣는 방식을 허용했다.
유일성을 보장받지 못하니 사용하지 말 것을 권장한다.
C++14에 나온 방식
* 이 방식으로 유니크 포인터 객체를 생성하기를 권장한다.
unique_ptr<Dog> dog = make_unique<Dog>(10, "까망이");
* new 키워드를 명시적으로 사용하지 않는다.
내부적으로 매개변수를 사용해 new를 호출한다.
* make_unique<>()는 매개변수에 포인터를 없다.
즉, 원시 포인터를 얻을 수 있는 방법이 없기 때문에
중복 사용을 막을 수 있다.
* make_unique<>() 사용을 권장한다.
귀여운 그림은 낡은 창고님이 그리셨습니다.
'C++' 카테고리의 다른 글
[C++] STL - vector (0) | 2022.12.22 |
---|---|
[C++] STL - Standard Template Library (0) | 2022.12.22 |
[C++] 참조 Reference (8) | 2022.07.04 |
[C++] 가상 소멸자 (0) | 2022.07.02 |
[C++] 동적 바인딩, 정적 바인딩 (1) | 2022.06.30 |