<개요> 이번엔 auto_ptr 부터 weak_ptr 까지 모든 스마트 포인터들에 대해 작성합니다. |
<auto_ptr> auto_ptr은 TR1 부터 생성됐던 스마트 포인터의 시초입니다. 사용자가 깜빡 할 수 있는 동적할당 된 객체의 파괴를 대신 해줄 객체를 만드는 것입니다. auto_ptr은 C++11 부터 사용 중지 권고, C++17 부터 제거 됐습니다. (현재 vs2017 내에선 살아있습니다;)
auto_ptr은 기본적으로 배열을 사용하지 않는 동적할당에서, 한 개체값에 대해서만 사용해야 합니다. 무슨말인고하니, auto_ptr은 동적할당된 배열을 삭제시키지 않습니다.
A는 int의 0번째 배열에 대한 정보를 가지고 있을 뿐, 1번째부턴 접근할 수 있는 방법이 없습니다. ( (*A) + 1 이런 식으로 접근은 가능합니다만은... )
auto_ptr의 소멸자는 이런식으로 구현이 돼있습니다. 배열 단위의 해제는 해주지 않습니다. 또한 위의 예제와 같이 auto_ptr은 값 단위 복사를 할 수 없습니다. 단지 소유권 이동입니다. 위의 상황때문에 auto_ptr은 사용 중지 권고가 됐고, 대신 더 강력하고 auto_ptr을 대체할 unique_ptr이 등장했습니다. <unique_ptr>
unique_ptr은 위와 같이 구성돼있습니다. unique_ptr을 효과적으로 생성하려면 make_unique 도우미 함수를 이용하면 됩니다. ( make_unique는 내부적으로 동적 할당을 실행합니다! ) get 함수는 현재 unique_ptr이 가지고 있는 객체를 불러옵니다.
unique_ptr로 배열을 감싸려면 꼭 unique_ptr<int[]> 로 선언하셔야 합니다!!! 이렇게 선언하지않으면 내부에선 delete _Myptr; 을 호출합니다. reset 함수는 객체를 파괴시키고 빈 값을 가집니다. 하지만 reset 함수와 동시에 값을 집어 넣을 수 있습니다.
release 함수는 객체를 파괴시키지 않고, 포인터만 뱉어내고 unique_ptr을 null로 만듭니다. 이 결과 뱉어낸 포인터의 소멸자는 사용자가 직접 호출해주어야 합니다.
swap 함수는 두 unique_ptr 간의 포인터(객체) 를 교환합니다.
응용하여 unique_ptr의 factory 함수를 만들어 낼 수도 있습니다.
마찬가지로 vector, list등 컨테이너에도 사용 가능합니다.
<shared_ptr> shared_ptr은, unique_ptr 에서 각 스마트 포인터들이 같은 값을 가지지 못하는 것을 보안하기 위해 등장했습니다. 내부에선 참조 카운팅 방법을 사용하며, 0이 되면 삭제됩니다. shared_ptr 또한 make_shared 라는 도우미 함수가 존재합니다. 기본적으론 unique_ptr의 함수와 동일하므로, 다른 함수만 작성하겠습니다.
shared_ptr a가 객체를 가지게 되면, a는 count를 1 증가 시킵니다. 만약 대입이 일어나 b가 a 와 같은 값을 가지게 되면, count를 1 증가시켜 2로 바꿉니다. 그렇게 a 와 b 의 소멸자가 호출이 된다면, count 가 1이 아니면 count 를 감소만 시켜주고 소멸자를 빠져 나옵니다. 만약 a가 제거 됐다면 count 는 다시 1로 줄어들 것이고, b가 제거되면서 count 가 1이니 객체인 new int(5) 를 삭제해주는 방식입니다. use_count 함수는 현재 shared_ptr이 가지고 있는 객체의 참조 카운터가 몇인지 알려줍니다.
unique 함수는 현재 객체가 고유한지 알려줍니다.
위 결과 a 는 b 와 똑같은 객체를 가르키고 있기 때문에 false 가 나옵니다. ( use_count를 사용하는 방식 ) shared_ptr은 비멤버 함수로 pointer의 형변환을 지원합니다.
shared_ptr은 순환참조의 문제점이 있기 때문에 각별히 유의해야 한다.
대부분 순환참조는 shared_ptr이 가지고 있는 객체의 멤버가 shared_ptr이 있을때 나타나게 되는데, 위처럼 멤버변수가 다른 shared_ptr을 참조하는 경우이다. 이 경우, myA는 empty가 되지만 myA가 가지고 있는 A(1) 객체는 사라지지 않는다. 거기서 만약 myB의 m_other이 다른 객체를 참조하게 된다면 A(1)은 영원히 존재하게 된다. 위의 순환 참조를 없애기 위해 나온 대안이 weak_ptr 이다. <weak_ptr> weak_ptr은 shared_ptr을 참조할 수 있게 해주는 스마트 포인터로써, 참조는 하지만 reference count는 증가시키지 않는다. 위와 같은 순환 참조를 막는데 주로 사용된다.
위 처럼 a 의 reference count는 1 이 된다. ( 여담 : reference count 에도 strong 과 weak가 존재한다고 한다. shared가 shared를 참조하면 strong count가 올라가고 weak가 weak 또는 shared를 참조하면 weak count가 올라간다고 한다 . 불론 weak count는 shared의 소멸자에 영향을 주지 않음 내용 : http://egloos.zum.com/sweeper/v/3059940 ) weak_ptr은 그 자체만으로는 shared_ptr의 값에 접근하지 못한다. 접근하려면 lock 함수를 사용해 shared_ptr로 convert 한 후 접근하여야 한다. expired 함수는 자신이 참조하고있는 shared_ptr이 존재 하는가에 대해 반환한다.
expired는 존재하지않는다면 true를, 존재한다면 false를 리턴한다. 음 대충 작성한 것 같은데, 더 붙힐게 생각나거나 보완해야할 점이 보이면 바로바로 수정하겠다. |
'C++ > Modern' 카테고리의 다른 글
C++14) 자료형이 다른 연관 컨테이너의 조회 ( Heterogeneous lookup in associative containers ) (0) | 2019.02.22 |
---|---|
C++14) 일반화 람다 ( Generic lambda ) (0) | 2019.02.20 |
C++11) std::reference_wrapper (0) | 2019.02.14 |
C++11) 사용자 정의 리터럴 (0) | 2019.02.13 |
C++11) extern template (0) | 2019.02.13 |