1. 程式人生 > >c++智慧指標(smart pointer)詳解

c++智慧指標(smart pointer)詳解

Smart Pointer

Deal with c++11’s smart pointer facility.

brief

Smart pointers are class objects that behave like built-in pointers but also manage objects that you create with new so that you don’t have to worry about when and whether to delete them - the smart pointers automatically delete the
managed object for you at the appropriate time.

  • shared_ptr
  • weak_ptr
  • unique_ptr

shared_ptr (共享指標)

  • referenced-counted smart pointer
  • Shared Ownership with shared_ptr

引用計數智慧指標:可以和其他 boost::shared_ptr 型別的智慧指標共享所有權。 在這種情況下,當引用物件的最後一個智慧指標銷燬後或者被重新賦值或者使用了reset(),物件才會被釋放。多個shared_ptr物件可以擁有同一個物件。

在繼承中的例子:

    shared_ptr<Thing> base_ptr(new
Thing(2)); shared_ptr<Food> derived_ptr; ///if static_cast<Derived* >(base_ptr.get()) is valid, then the following is valid: base_ptr->showID(); ///cast failed derived_ptr = static_pointer_cast<Food>(base_ptr); shared_ptr<Food> a(new Food); // a->showID();
derived_ptr->showID();

使用 make_shared 更加高效

There are actually two dynamic memory allocations that happen: one for the object itself from the new, and then a second for the manager object created by the shared_ptr constructor. Since memory allocations are slow, this means that creating a shared_ptr is slow relative to using either a raw pointer, or a so-called “intrusive” reference- counted smart pointer where the reference count is a member variable of the object. To address this problem, C++11 includes a function template make_shared that does a single memory allocation big enough to hold both the manager object and the new object, passing along any constructor parameters that you specify, and returns a shared_ptr of the specified type, which can then be used to initialize the shared_ptr that you are creating (with efficient move semantics).


    shared_ptr<Thing> p(new Thing); // ouch - two allocations
    shared_ptr<Thing> p1(make_shared<Thing>()); // only one allocation!

注意

  • 使用 share_ptr copy assignment 或者建構函式會使shared_ptr的引用計數加1
  • 使用 reset() 成員函式可以使當前share_ptr為空,刪除指向物件的指標
  • 通過給share_ptr賦值 nullptr 可以達到第二條的效果
  • 不允許原生指標與智慧指標之間的直接賦值轉換
  • 不要直接從原生指標構造兩個功能相同的smart pointer,否則會造成double-deletion錯誤
  • 可以通過 get() 函式獲得原生指標
  • 在繼承關係或者其他的轉換時,可以使用
    • static_pointer_cast
    • dynamic_pointer_cast
    • const_pointer_cast

weak_ptr

Weak pointers just “observe” the managed object; they don’t “keep it alive” or affect its lifetime. Unlike shared_ptrs, when the last weak_ptr goes out of scope or disappears, the pointed-to object can still exist because
the weak_ptrs do not affect the lifetime of the object - they have no ownership rights. But the weak_ptr can be used to determine whether the object exists, and to provide a shared_ptr that can be used to refer to it.

僅僅觀察被管理的物件,對其生命週期不產生任何影響

1.weak_ptr build-in-pointer might zero.

void do_it(weak_ptr<Thing> wp){
shared_ptr<Thing> sp = wp.lock();
// get shared_ptr from weak_ptr 
        if(sp)
          sp->defrangulate(); // tell the Thing to do something
        else
          cout << "The Thing is gone!" << endl;
}

2.This approach is useful as a way to simply ask whether the pointed-to object still exists.

 bool is_it_there(weak_ptr<Thing> wp) {
       if(wp.expired()) {
          cout << "The Thing is gone!" << endl;
          return false;
          }
       return true;
   }

3.if the weak_ptr is expired, an exception is thrown, of type
std::bad_weak_ptr.


void do_it(weak_ptr<Thing> wp){
shared_ptr<Thing> sp(wp); // construct shared_ptr from weak_ptr
 // exception thrown if wp is expired, so if here, sp is good to go sp->defrangulate();
  // tell the Thing to do something
}
   try {
          do_it(wpx);
       }
       catch(bad_weak_ptr&)
       {
          cout << "A Thing (or something else) has disappeared!" << endl;
       }

4.inherit from enabled_shared_from_this\

否則會出現的錯誤 error:pointer being freed was not allocated

class Thing:public enable_shared_from_this<Thing>{
public:
    int id;
public:
    virtual void showID() const;
    Thing();
    Thing(int _id);
    void foo();

};
void Thing::foo() {
    shared_ptr<Thing> t1 = shared_from_this();
    t1->showID();

}

公有繼承enable_shared_from_this\ ,則Thing類有了一個weak_ptr 作為成員變數。當第一個shared_ptr建立時,從第一個shared_ptr中初始化該weak_ptr\,當需要一個指向this的share_ptr時呼叫shared_from_this()成員函式,返回一個由weak_prt\構造而來的shared_ptr\,使得返回的shared_ptr與第一次的shared_ptr是相同的 manage object.

注意

  • weak_ptr 與 share_ptr 結合使用,僅通過從share_ptr的複製和賦值,或者來源與其他weak_ptr。
  • lock() 函式檢查weak_ptr指向的物件是否存在,如果不存在返回一個空的share_ptr,否則返回一個指向該物件的share_ptr.
  • 不能使用給weak_ptr賦值nullptr的方式,只能通過reset()方法
  • expired()函式返回weak_ptr是否為存在非空物件。
  • 在建構函式中不可以使用shared_from_this
  • 儘可能多的搭配使用share_ptr和weak_ptr,自動化記憶體管理。

unique_ptr

With a unique_ptr, you can point to an allocated object, and when the unique_ptr goes out of scope, the pointed-to object gets deleted, and
this happens regardless of how we leave the function, either by a return or an exception being thrown somewhere.

unique_ptr implements a unique ownership concept - an object can be owned by only one unique_ptr at a time - the opposite of shared ownership.

unique_ptr 隱式的刪除了copy建構函式,和copy assignment操作符,不允許一個物件同時被多個unique_ptr擁有這恰恰與shared_ptr相反。

The unique ownership is enforced by disallowing (with =delete) copy construction and copy assignment.So unlike built-in pointers or shared_ptr, you can’t copy or assign a unique_ptr to another unique_ptr.

move semantics: the move constructor and move assignment operator are defined for unique_ptr so that they transfer ownership from the original owner to the new owner.

可以通過move建構函式和move assignment 操作符使得unique_ptr的所屬權從原來的轉移到新的。轉移之後原來的unique_ptr不包含任何物件。

隱式的從右值轉換

 unique_ptr<Thing> create_Thing()
   {
       unique_ptr<Thing> local_ptr(new Thing);
       return local_ptr;  // local_ptr will surrender ownership
   }
void foo() {
       unique_ptr<Thing> p1(create_Thing()); // move ctor from returned rvalue
        // p1 now owns the Thing
        unique_ptr<Thing> p2; // default ctor'd; owns nothing
        p2 = create_Thing(); // move assignment from returned       rvalue // p2 now owns the second Thing
}

顯式的使用move assignment 和 move construction進行轉換

unique_ptr<Thing> p1(new Thing); // p1 owns the Thing
unique_ptr<Thing> p2; // p2 owns nothing
// invoke move assignment explicitly
p2 = std::move(p1); // now p2 owns it, p1 owns nothing
// invoke move construction explicitly
unique_ptr<Thing> p3(std::move(p2)); // now p3 owns it, p2 and p1 own nothing 

注意

  • 通過reset()函式或者給unique_ptr賦值nullptr,可以手工的刪除物件。

reference

相關推薦

c++智慧指標(smart pointer)

Smart Pointer Deal with c++11’s smart pointer facility. brief Smart pointers are class objects that behave like built-in

C++ 智慧指標(Smart Pointer)

智慧指標具有非常強大的能力,謹慎而明智的選擇能帶來極大的好處。我不否認智慧指標的能力,雖然我在之前的否認過auto_ptr。可能由於我自身能力的限制,體會不到auto_ptr的好處,但這樣的可能性我覺得已經不大了。但auto_ptr是最簡單的智慧指標,在它的周圍存在大量的作品

C++中的智慧指標(smart pointer)

指標問題是在學習C++,以及運用C++進行軟體開發過程中經常碰到的問題。其中之一,就是“懸垂指標”。所謂懸垂指標,就是是指指標指向了一塊沒有分配給使用者使用的記憶體,結果未定義,往往導致程式錯誤,而且難以檢測。 用一個簡單的例子來說明懸垂指標: string *sp = n

C++】智慧指標(Smart Pointer)

1. 傳統指標存在的問題 傳統指標存在諸多的問題,比如指標所指向的物件的生命週期問題,掛起引用(dangling references),以及記憶體洩露(memory leaks). 如下是一個傳統指標的使用過程 void Foo() {

[C++] 什麼是智慧指標(Smart Pointer)以及何時使用

答案 1 智慧指標是一個類,它封裝了一個原始的C++指標,以管理所指物件的生命期。沒有單一的智慧指標型別,但所有這些都嘗試以實用的方式抽象原始指標。 智慧指標應優先於原始指標。 如果你覺得你需要使用指標(首先要考慮你是否真的需要指標),你通常會想要使用智慧指

C++深度探索系列:智慧指標(Smart Pointer) [二]

                                           深度探索智慧指標(Smart Pointer) 主題索引: 一、剖析C++標準庫智慧指標(std::auto_ptr)        1.Do you Smart Pointer?    2

C++ 函式指標及其作用

查了很多資料,對函式指標已瞭解。 函式指標指向某種特定型別,函式的型別由其引數及返回型別共同決定,與函式名無關。舉例如下: int add(int nLeft,int nRight);//函式定義    該函式型別為int(

智慧指標(smart pointer)(2):unique_ptr

Unique pointer:   Manages the storage of a pointer, providing a limited garbage-collection facility, with little to no overhead ov

智慧指標boost::weak_ptr

1、boost::weak_ptr簡介 boost::weak_ptr屬於boost庫,定義在namespace boost中,包含標頭檔案 #include<boost/weak_ptr.hpp>便可以使用。 2、boost::weak_ptr

深度探索智慧指標(Smart Pointer)

主題索引: 一、剖析C++標準庫智慧指標(std::auto_ptr)        1.Do you Smart Pointer?    2.std::auto_ptr的設計原理    3.std::auto_ptr高階使用指南    4.你是否覺得std::auto_p

C++ 智慧指標

C++ 智慧指標詳解   一、簡介 由於 C++ 語言沒有自動記憶體回收機制,程式設計師每次 new 出來的記憶體都要手動 delete。程式設計師忘記 delete,流程太複雜,最終導致沒有 de

c++智慧指標

C++ 智慧指標詳解 一、簡介 由於 C++ 語言沒有自動記憶體回收機制,程式設計師每次 new 出來的記憶體都要手動 delete。程式設計師忘記 delete,流程太複雜,最終導致沒有 delete,異常導致程式過早退出,沒有執行 delete 的情況並不罕見。

C++ this指標 C++中this指標的用法

C++中this指標的用法詳解   轉自:http://blog.chinaunix.net/uid-21411227-id-1826942.html 1. this指標的用處:   一個物件的this指標並不是物件本身的一部分,不會影響sizeof(物件)的結果

c++中this指標的用法

為什麼引入this指標?     最簡單的應用場景就是:當我們在類中定義了一個變數,同時在類成員函式中定義了同一變數時,也就是說變數名重複時,但是我們想使用類中定義的變數,這個時候我們該怎麼辦呢?這個時候就是this指標大顯身手的時候了。為此我們引入this指標

C++ 中 this 指標的用法

1. this指標的用處: 一個物件的this指標並不是物件本身的一部分,不會影響sizeof(物件)的結果。this作用域是在類內部,當在類的非靜態成員函式中訪問類的非靜態成員的時候,編譯器會自動將物件本身的地址作為一個隱含引數傳遞給函式。也就是說,即使你沒有寫上

C++拷貝構造函數

public 類對象 -m 都是 出錯 ons const 需要 new 轉自:http://blog.csdn.net/lwbeyond/article/details/6202256/ 一. 什麽是拷貝構造函數 首先對於普通類型的對象來說,它們之間的復制是很簡單的,例如

C++11 std::chrono庫

toolbar space max mil exp 值類型 cond 精度 ++i 所謂的詳解只不過是參考www.cplusplus.com的說明整理了一下,因為沒發現別人有詳細講解。   chrono是一個time library, 源於boost,現在已經是C++標準。

C++ 智能指針(轉)

include 復雜 測試類 信息 思想 編譯 應該 其他 eas C++ 智能指針詳解 一、簡介 由於 C++ 語言沒有自動內存回收機制,程序員每次 new 出來的內存都要手動 delete。程序員忘記 delete,流程太復雜,最終導致沒有 delete,異常導致程

【轉】 C語言文件操作

pri void rfi 識別 archive format 隨機 stat 文本文 轉自:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html C語言中沒有輸入輸出語句,所有的輸入輸出功能都用

關於windows下的c++的rand函數

c++ rand rand不是真正的隨機函數,是偽隨機函數srand設置隨機函數種子srand設置一個參數後,每調用一次rand產生一個隨機數srand(1000001)rand – 21589rand – 29335rand – 14469 srand參數相同,多次調用rand依次返回的