37
C++11 Smart Pointers 2015-03-10 Matthew

C++11 smart pointers

Embed Size (px)

Citation preview

Page 1: C++11 smart pointers

C++11 Smart Pointers2015-03-10 Matthew

Page 2: C++11 smart pointers

Outline

● Why smart pointer?● std::unique_ptr● std::shared_ptr● std::weak_ptr● Conclusion

Page 3: C++11 smart pointers

Why smart pointer?

當我們拿到一個 Foo* ptr 時...

1. 你其實不知道它是單一物件還是 array.2. 你不知道該怎麼銷毀它.

a. delete ? delete[] ? ->Release()? Finalize()?

3. 保證(考慮所有路線可能後)剛好 delete 一次.4. 你不知道這個指標是否還有效...

…from Effective Modern C++

Page 4: C++11 smart pointers

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.

Page 5: C++11 smart pointers

for exclusive-ownership

std::unique_ptr

Page 6: C++11 smart pointers

std::uniqre_ptr

● 最簡單的 smart pointer● 適用於物件只有一個 owner 時● 當 unique_ptr 消滅時, 會順帶釋放持有資源.

Page 7: C++11 smart pointers

適用場景

void f()

{

ClassA* ptr = new ClassA; … // do something

delete ptr;

}

if ( error ) { return; }

Page 8: C++11 smart pointers

適用場景

void f()

{

std::unique_ptr<ClassA> ptr(new ClassA);

… // do something

if ( error ) { return; }

//delete ptr; no longer necessary.

}

Page 9: C++11 smart pointers

建立 unique_ptr

// 傳入 raw pointer

unique_ptr< string > up( new string("nico") );

// 使用 make_unique function

auto up = make_unique< string >( "nico" );

Page 10: C++11 smart pointers

std::unique_ptr 用法

// unique_ptr 覆寫了 *, -> 運算子

// 所以用法和一般 pointer 差不多

(*up)[0] = 'N';

up->append("lai");

cout << *up << endl;

Page 11: C++11 smart pointers

std::unique_ptr 管理動態分配陣列

// 也可以管理陣列, 用[]運算子存取

unique_ptr< int[] > up2( new int[10] );

for ( int i = 0; i < 10; ++i)

cout << up2[ i ];

Page 12: C++11 smart pointers

std::unique_ptr 檢查

// 檢查指標有效性

if ( up ) { … }

if ( up != nullptr ) { … }

// 釋放所有權 (立刻釋放資源)

up.release();

Page 13: C++11 smart pointers

std::unique_ptr 用法

// 不接受隱式轉換成 raw pointer (Compiler Error!)

unique_ptr<string> up = new string("");

string* p = up;

// 如果你真的要取得 raw pointer…string* p = up.get(); //後果自行負責

Page 14: C++11 smart pointers

// 不能分享所有權, 也不能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

Page 15: C++11 smart pointers

std::unique_ptr tips

vector< unique_ptr<string> > kVec;

// up 不能複製, 要用 reference 的方式取

for ( auto& up : kVec )

{

cout << *up;

}

Page 16: C++11 smart pointers

std::unique_ptr 很適合持有 memberclass MyClass

{

unique_ptr<Foo> m_spFoo;

public:

MyClass() : m_spFoo( make_unique<Foo>( 1, "Bar" ) ) {}

~MyClass() { /* 不需要在 destructor 釋放資源 */ }

void DoSomething()

{

m_spFoo->bar();

}

};

Page 17: C++11 smart pointers

for shared-ownership.

std::shared_ptr

Page 18: C++11 smart pointers

std::shared_ptr 概念

● 由多個物件共享該資源的持有權

● 允許多個 smart pointer 指向同一個物件

● 只有所有的 shared_ptr 都消滅後,才會釋放

持有資源 (reference count)

Page 19: C++11 smart pointers

建立 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" );

Page 20: C++11 smart pointers

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 ) { … }

Page 21: C++11 smart pointers

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

Page 22: C++11 smart pointers

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

Page 23: C++11 smart pointers

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 );

}

Page 24: C++11 smart pointers

specify deleter// shared_ptr 可以指定釋放資源的方式

FILE* fp = fopen("log.txt", "w");

shared_ptr<FILE> sp( fp, [] ( FILE* f )

{

cout << "File Closed!";

fclose(f);

} );

Page 25: C++11 smart pointers

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 );

}

Page 26: C++11 smart pointers

if pointers that can dangle.

std::weak_ptr

Page 27: C++11 smart pointers

std::weak_ptr 概念

● 有時候我們不希望共享物件的"持有權"…● 但是又不想用 raw pointer…

● 用 weak_ptr!● weak_ptr 可以存取 shared_ptr 管理的物件,

但是不會增加 ref count.

Page 28: C++11 smart pointers

避免 reference cycle

Bank

Customershare_ptr<Customer>

share_ptr<Bank>

無法自動釋放!!share_ptr<Bank>

Page 29: C++11 smart pointers

避免 reference cycle

Bank

Customershare_ptr<Customer>

weak_ptr<Bank>

自動釋放OK!!share_ptr<Bank>

Page 30: C++11 smart pointers

建立 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 );

Page 31: C++11 smart pointers

weak_ptr 用法

// weak_ptr 「沒有」覆寫 *, -> 運算子

// 所以不能像一般 pointer 使用

weak_ptr< string > wp( sp );

(*wp)[0] = 'N'; // Compiler Error!

wp->append("lai"); // Compiler Error!

Page 32: C++11 smart pointers

// 必須呼叫 lock() 轉成 share_ptr 才能用

weak_ptr< string > wp( sp2 );

if ( auto& sp = wp.lock() )

{

sp->append( "lai" );

cout << *sp;

}

else

{

cout << "Object is deleted.";

}

Page 33: C++11 smart pointers

weak_ptr 用法

weak_ptr< string > wp( sp );

// weak_ptr 可以 copy

weak_ptr< string > wp2 = wp;

wp.reset(); // 釋放物件指標

wp.expired(); // 詢問物件還在否?

Page 34: C++11 smart pointers

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!

Page 35: C++11 smart pointers

Dangerous! Don't do that.

CImage* pImage = new CImage;

// 不要用兩個 smart pointer 管理同一個 raw pointer !!

share_ptr<CImage> sp( pImage );

share_ptr<CImage> sp2( pImage );

Page 36: C++11 smart pointers

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)

Page 37: C++11 smart pointers

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)