Upgrade to Pro — share decks privately, control downloads, hide ads and more …

C++11 Smart Pointers

Matt
March 11, 2015

C++11 Smart Pointers

Matt

March 11, 2015
Tweet

More Decks by Matt

Other Decks in Technology

Transcript

  1. Why smart pointer? 當我們拿到一個 Foo* ptr 時... 1. 你其實不知道它是單一物件還是 array.

    2. 你不知道該怎麼銷毀它. a. delete ? delete[] ? ->Release()? Finalize()? 3. 保證(考慮所有路線可能後)剛好 delete 一次. 4. 你不知道這個指標是否還有效... …from Effective Modern C++
  2. Smart pointer! • C++11 引入三種 smart pointer 來管理資源. • #include

    <memory> • unique_ptr: for exclusive-ownership. • share_ptr: for shared-ownership. • weak_ptr: if pointers that can dangle.
  3. 適用場景 void f() { ClassA* ptr = new ClassA; …

    // do something delete ptr; } if ( error ) { return; }
  4. 適用場景 void f() { std::unique_ptr<ClassA> ptr(new ClassA); … // do

    something if ( error ) { return; } //delete ptr; no longer necessary. }
  5. 建立 unique_ptr // 傳入 raw pointer unique_ptr< string > up(

    new string("nico") ); // 使用 make_unique function auto up = make_unique< string >( "nico" );
  6. std::unique_ptr 用法 // unique_ptr 覆寫了 *, -> 運算子 // 所以用法和一般

    pointer 差不多 (*up)[0] = 'N'; up->append("lai"); cout << *up << endl;
  7. std::unique_ptr 檢查 // 檢查指標有效性 if ( up ) { …

    } if ( up != nullptr ) { … } // 釋放所有權 (立刻釋放資源) up.release();
  8. std::unique_ptr 用法 // 不接受隱式轉換成 raw pointer (Compiler Error!) unique_ptr<string> up

    = new string(""); string* p = up; // 如果你真的要取得 raw pointer… string* p = up.get(); //後果自行負責
  9. // 不能分享所有權, 也不能copy unique_ptr unique_ptr<string> up2 = up; (Compiler Error!)

    // 要用 std::move 顯式轉移 unique_ptr<string> up2 = std::move(up); // 轉移之後up失去所有權, onwer 變成了up2 cout << (up == nullptr); // true cout << (up2 == nullptr); // false
  10. std::unique_ptr tips vector< unique_ptr<string> > kVec; // up 不能複製, 要用

    reference 的方式取 for ( auto& up : kVec ) { cout << *up; }
  11. std::unique_ptr 很適合持有 member class MyClass { unique_ptr<Foo> m_spFoo; public: MyClass()

    : m_spFoo( make_unique<Foo>( 1, "Bar" ) ) {} ~MyClass() { /* 不需要在 destructor 釋放資源 */ } void DoSomething() { m_spFoo->bar(); } };
  12. std::shared_ptr 概念 • 由多個物件共享該資源的持有權 • 允許多個 smart pointer 指向同一個物件 •

    只有所有的 shared_ptr 都消滅後,才會釋放 持有資源 (reference count)
  13. 建立 std::shared_ptr // 傳入 raw_pointer shared_ptr<string> sp( new string("nico") );

    // 呼叫 make_shared function (Recommend!) // make_shared is more efficient. auto sp = make_shared<string>( "nico" );
  14. std::shared_ptr 用法 auto sp = make_shared<string>( "nico" ); cout <<

    (*sp)[ 0 ]; // print 'n' sp->replace(0, 1, 'N'); // "Nico" string* p = sp.get(); // get raw pointer if ( sp ) { … } if ( sp != nullptr ) { … } if ( sp == nullptr ) { … }
  15. std::shared_ptr 可以分享持有權 auto sp = make_shared< QImage >( "icon.png" );

    auto sp2( sp ); // via copy constructor auto sp3 = sp; // via assignment DoSomething( sp ); // pass as parameter sp.reset(); // 釋放所有權 sp2.reset( new QImage ); // 改持有另一個 raw ptr
  16. std::shared_ptr 可以分享持有權 auto sp = make_shared< string >( "nico" );

    auto sp2 = sp; vector< shared_ptr<string> > kVec; kVec.push_back( sp ); kVec.push_back( sp2 ); cout << sp.use_count() << endl; // 4
  17. specify deleter // shared_ptr 可以指定釋放資源的方式 FILE* fp = fopen("log.txt", "w");

    shared_ptr<FILE> sp( fp, CloseFile ); void CloseFile( FILE* f ) { cout << "File Closed!"; fclose( f ); }
  18. specify deleter // shared_ptr 可以指定釋放資源的方式 FILE* fp = fopen("log.txt", "w");

    shared_ptr<FILE> sp( fp, [] ( FILE* f ) { cout << "File Closed!"; fclose(f); } );
  19. type cast // static_pointer_cast() // dynamic_pointer_cast() // const_pointer_cast() void f(

    share_ptr<CBase> spBase ) { share_ptr<CNode> spNode = dynamic_pointer_cast< CNode >( spBase ); }
  20. std::weak_ptr 概念 • 有時候我們不希望共享物件的"持有權"… • 但是又不想用 raw pointer… • 用

    weak_ptr! • weak_ptr 可以存取 shared_ptr 管理的物件, 但是不會增加 ref count.
  21. 建立 weak_ptr // weak_ptr 不能單獨存在! weak_ptr<QImage> wp( new QImage );

    // 必須依附於 shared_ptr. shared_ptr<QImage> sp( new QImage("icon.png") ); weak_ptr<QImage> wp( sp );
  22. weak_ptr 用法 // weak_ptr 「沒有」覆寫 *, -> 運算子 // 所以不能像一般

    pointer 使用 weak_ptr< string > wp( sp ); (*wp)[0] = 'N'; // Compiler Error! wp->append("lai"); // Compiler Error!
  23. // 必須呼叫 lock() 轉成 share_ptr 才能用 weak_ptr< string > wp(

    sp2 ); if ( auto& sp = wp.lock() ) { sp->append( "lai" ); cout << *sp; } else { cout << "Object is deleted."; }
  24. weak_ptr 用法 weak_ptr< string > wp( sp ); // weak_ptr

    可以 copy weak_ptr< string > wp2 = wp; wp.reset(); // 釋放物件指標 wp.expired(); // 詢問物件還在否?
  25. auto sp = make_shared<string>( "Hello" ); weak_ptr<string> wp( sp );

    cout << *sp ; // print 'Hello' cout << *wp.lock() ; // print 'Hello' cout << wp.expired(); // print 'false' sp.reset(); // release resource. cout << wp.expired(); // print 'true' cout << *wp.lock(); // throw exception!
  26. Dangerous! Don't do that. CImage* pImage = new CImage; //

    不要用兩個 smart pointer 管理同一個 raw pointer !! share_ptr<CImage> sp( pImage ); share_ptr<CImage> sp2( pImage );
  27. Conclusion • C++11 想要消滅 delete keyword. • C++11 想要消滅 90%

    的 new keyword. • 思考資源的持有權, 來挑選 smart pointer. • 如果不確定要用哪個, 先選 unique_ptr ◦ 因為 unique_ptr 幾乎沒有 cost • share_ptr 有一些 cost ◦ double pointer size (space cost) ◦ reference count. (performance cost)
  28. Reference • http://www.cplusplus.com/reference/memory/ • MSDN: How to: Create and Use

    shared_ptr Instances • The C++ Standard Library 2ed. (Book) • Effective Modern C++ (Book)