2018년 5월 21일 월요일

C++ 11/14 관련 내용 대충 정리, shared_ptr

최신 C++을 공부하려 책을 보긴 했었는데
내용이 기존 문법과 함께 여기저기 흩어져 있어 보기에 좀 어려워
MSDN을 참고하여 대충 정리하려함.

C++11/14/17 기능에 대한 지원(최신 C++)
https://msdn.microsoft.com/ko-kr/library/hh567368.aspx


shared_ptr

https://msdn.microsoft.com/ko-kr/library/hh279669.aspx


- 여러곳에서 참조하는 개체의 수명을 관리하기 위한 C++ STL 스마트 포인터
- shared_ptr 를 초기화 한 후에 복사, 함수 인수를 값으로 전달 및 다른 shared_ptr 인스턴스로 할당 가능
- 참조 횟수가 0에 도달하면 참조개체와 내부 제어 블록을 삭제





    // Use make_shared function when possible.
    auto sp1 = make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You");

    // Ok, but slightly less efficient. 
    // Note: Using new expression as constructor argument
    // creates no named variable for other code to access.
    shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance"));

    // When initialization must be separate from declaration, e.g. class members, 
    // initialize with nullptr to make your programming intent explicit.
    shared_ptr<Song> sp5(nullptr);
    //Equivalent to: shared_ptr<Song> sp5;
    //...
    sp5 = make_shared<Song>(L"Elton John", L"I'm Still Standing");

- 되도록이면 예외 발생 상황에서 문제 없는 make_shared를 사용하여 만들어라.

    vector<shared_ptr<MediaAsset>> assets;

    assets.push_back(shared_ptr<Song>(new Song(L"Himesh Reshammiya", L"Tera Surroor")));
    assets.push_back(shared_ptr<Song>(new Song(L"Penaz Masani", L"Tu Dil De De")));
    assets.push_back(shared_ptr<Photo>(new Photo(L"2011-04-06", L"Redmond, WA", L"Soccer field at Microsoft.")));

    vector<shared_ptr<MediaAsset>> photos;

    copy_if(assets.begin(), assets.end(), back_inserter(photos), [] (shared_ptr<MediaAsset> p) -> bool
    {
        // Use dynamic_pointer_cast to test whether
        // element is a shared_ptr<Photo>.
        shared_ptr<Photo> temp = dynamic_pointer_cast<Photo>(p);  
        return temp.get() != nullptr;
    });

    for (const auto&  p : photos)
    {
        // We know that the photos vector contains only 
        // shared_ptr<Photo> objects, so use static_cast.
        wcout << "Photo location: " << (static_pointer_cast<Photo>(p))->location_ << endl;
    }

- dynamic_pointer_cast, static_pointer_cast, const_pointer_cast를 사용하여 shared_ptr를 캐스팅할 수 있음.

- shared_ptr는 다음의 방법으로 다른 함수에 전달할 수 있음.
 : 값(value)으로 전달 (복사 생성자 호출 => 참조 횟수 증가, 약간 오버 헤드 있음)
 : 참조(reference), const 참조로 전달 (참조횟수 증가 안함.)
 : 내부 포인터 또는 내부 개체에 대한 참조를 전달 (개체 공유, 단 참조 횟수는 증가하지 않음, 좀 위험.)

- shared_ptr 전달 방법을 결정할 때 고려 해야 하는 것은 호출 수신자(callee)가 소유권을 공유할 수 있는지를 판단해야 함.
 : shared_ptr가 call이 완료 될 때 까지 caller, callee 외 다른 소유자로 인해 shared_ptr의 유효함이 보장되면 값으로 전달하고, 보장되지 않는 경우라면 참조를 넘겨 callee가 알아서 판단하도록 한다.
- std:vector<shared_ptr<T>>에서 람다 식 본문 또는 명명된 함수 개체로 전달할 경우 람다, 함수 개체가 포인터를 저장하지 않는다면 참조로 전달한다.


 // Initialize two separate raw pointers.
    // Note that they contain the same values.
    auto song1 = new Song(L"Village People", L"YMCA");
    auto song2 = new Song(L"Village People", L"YMCA");

    // Create two unrelated shared_ptrs.
    shared_ptr<Song> p1(song1);    
    shared_ptr<Song> p2(song2);

    // Unrelated shared_ptrs are never equal.
    wcout << "p1 < p2 = " << std::boolalpha << (p1 < p2) << endl;
    wcout << "p1 == p2 = " << std::boolalpha <<(p1 == p2) << endl;

    // Related shared_ptr instances are always equal.
    shared_ptr<Song> p3(p2);
    wcout << "p3 == p2 = " << std::boolalpha << (p3 == p2) << endl; 

- 가리키는 개체의 값을 비교하는 것이 아니라  shared_ptr이 가리키는 개체를 비교해야 함.


Modern Effective C++에서 관련된 chapter는 다음과 같고
더 자세한 내용을 원한다면 책을 꼭 읽는 것을 추천.
단 Modern Effective C++이 처음이라면 Effective C++을 먼저 읽는 것을 추천.

Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14
http://a.co/0MIIC9k

Item 19: Use std::shared_ptr for shared-ownership resource management.
Item 21: Prefer std::make_unique and std::make_shared to direct use of new.

- std::shared_ptr의 크기는 생 포인터의 두배
 : custom deleter를 지정해도 std::shared_ptr 객체의 크기가 변하지 않음.
- 제어 블럭에서 reference count, weak reference count, custom deleter 등을 저장함.
 : std::make_shared는 항상 제어 블럭을 생성
 : std::unique_ptr, std::auto_ptr로 부터 std:shared_ptr 을 생성하면 제어 블록이 생성
 : raw pointer로 std::shared_ptr 생성하면 제어 블록이 생성
   단 하나의 raw pointer에서 여러 std::shared_ptr을 생성하면 문제 발생.
- std::shared_ptr로 관리되는 클래스에서 클래스의 this로 부터 shared_ptr을 생성할 때는 shared_from_this()를 사용해야 순환 참조 문제가 없음.
- 참조 횟수의 증가와 감소가 반드시 원자적 연산이어야 함.

댓글 없음:

댓글 쓰기