unique_ptr, shared_ptr 읽히기

Program Lang./C++ 2016. 12. 30. 14:45

1. 목적

c++ unique_ptr, shared_ptr 개인적인 정리


2. shared_ptr

C++98 표준안까지 사용되던 auto_ptr은 이제 더 이상 사용하지 않는 것이 권고 사항이다. C++11부터 지원하는 share_ptr을 간단히 말하면 객체의 자동 파괴를 수행하기 위해서 도입된 smart pointer 이다. 하지만 몇 가지 제약 사항은 여전히 존재한다. 제약 사항은 아래에서 하나씩 살펴보도록 하자.

일반적인 사용법은 테스트 코드에 주석으로 표기하였다. 자세한 사항은 standard 생성자 overriding을 참조하면 된다.

다만 주의해야 할 사항은 대입 연산은 explicit으로 처리되어 있기 때문에 암시적 대입연산은 동작하지 않는다.

또한 make_shared<> utility를 사용하는 것이 성능면에서 좋다.


2.1. shared_ptr 예제 (제약 사항 예제)

The C++ Standard Library 책의 예제는 너무 복잡하고 딱히 와 닿지도 않아서 어떤 블로그 소스 참조

하나의 객체에 대해서 서로 다른 shared_ptr로 참조하게 되면 소멸된 객체에 다시 소멸자를 호출하게 되어서 알 수 없는 동작을 수행하게 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <memory>
#include <string>
 
class Person
{
public:
    std::string name;
    //std::shared_ptr<Person> mfriend;
    std::weak_ptr<Person> mfriend;
     
    Person(const std::string& _name) : name(_name) {
        std::cout << __FUNCTION__ << ", " << __LINE__ << std::endl;
    }
     
    virtual ~Person() {
        std::cout << __FUNCTION__ << ", " << __LINE__ << std::endl;
    }
};
 
int main()
{
    // 임시객체 생성
    Person *pPerson = new Person("heesoon.kim");
     
    std::shared_ptr<Person> p1(pPerson , [](Person *p) {
        std::cout << "delete : " << p->name << std::endl;
        delete p;
    });
     
    std::shared_ptr<Person> p2(pPerson, [](Person *p) {
        std::cout << "delete : " << p->name << std::endl;
        delete p;
    });
     
    return 0;
}


<실행결과>

Start
Person, 14
delete : heesoon.kim
~Person, 18
delete : heesoon.kim
Segmentation fault
Finish


순환 참조의 문제점을 보여주는 예제로 weak_ptr<Person> 주석을 막고 shared_ptr<Person>을 사용하면 소멸자가 호출되지 않는다. 결론적으로 객체가 정상적으로 파괴되지 않는 문제가 발생한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <memory>
#include <vector>
#include <string>
 
class Person
{
public:
    std::string name;
    //std::shared_ptr<Person> mfriend;
    std::weak_ptr<Person> mfriend;
     
    Person(const std::string& _name) : name(_name) {
        std::cout << __FUNCTION__ << ", " << __LINE__ << std::endl;
    }
     
    virtual ~Person() {
        std::cout << __FUNCTION__ << ", " << __LINE__ << std::endl;
    }
};
 
int main()
{
    // 1. default shared_ptr usage
    //std::shared_ptr<Person> kim(new Person("kim"));
    //std::shared_ptr<Person> lee(new Person("lee"));
     
    // 2. user define delete function
    std::shared_ptr<Person> kim(new Person("kim"), [](Person *p) {
        std::cout << "delete : " << p->name << std::endl;
        delete p;
    });
     
    std::shared_ptr<Person> lee(new Person("lee"), [](Person *p) {
        std::cout << "delete : " << p->name << std::endl;
        delete p;
    });
     
    // 3. using utility make_shared usage
    //std::shared_ptr<Person> kim = std::make_shared<Person>("kim");
    //std::shared_ptr<Person> lee = std::make_shared<Person>("lee");
     
    std::cout << "( " << kim.use_count() << ", " << lee.use_count() << ")" << std::endl;
    kim->mfriend = lee;
    std::cout << "( " << kim.use_count() << ", " << lee.use_count() << ")" << std::endl;
    lee->mfriend = kim;
    std::cout << "( " << kim.use_count() << ", " << lee.use_count() << ")" << std::endl;
     
    return 0;
}


2.3. shared_ptr 예제 (제약 사항 예제)

smart pointer라고는 하지만 여전히 주의를 기울여야 할 것이 남아 있다. weak_ptr은 shared_ptr의 reference_count를 늘리지 않지만 shared_ptr이 관리하는 객체를 공유한다. 객체의 자원 관리는 shared_ptr로 하되 객체에 접근하여 필요한 동작을 수행 시에는 weak_ptr로 하는 것이 바람직해 보인다.

'Program Lang. > C++' 카테고리의 다른 글

[json-c] simple parsing example  (0) 2017.01.09
std::function 정리  (0) 2017.01.02
c++ pair 읽히기  (0) 2016.12.30
full version (pat, pmt, sdt)  (2) 2016.07.22
sdt json version  (0) 2016.07.22
: