1. 程式人生 > 程式設計 >C++11 智慧指標之shared_ptr程式碼詳解

C++11 智慧指標之shared_ptr程式碼詳解

C++中的智慧指標首先出現在“準”標準庫boost中。

隨著使用的人越來越多,為了讓開發人員更方便、更安全的使用動態記憶體,C++11也引入了智慧指標來管理動態物件。

在新標準中,主要提供了shared_ptr、unique_ptr、weak_ptr三種不同型別的智慧指標。

接下來的幾篇文章,我們就來總結一下這些智慧指標的使用。

今天,我們先來看看shared_ptr智慧指標。

shared_ptr 智慧指標

shared_ptr是一個引用計數智慧指標,用於共享物件的所有權也就是說它允許多個指標指向同一個物件。這一點與原始指標一致。

先來一段簡單的程式碼,看看shared_ptr的簡單使用:

#include <iostream>
#include <memory>
using namespace std;

class Example
{
public:
 Example() : e(1) { cout << "Example Constructor..." << endl; }
 ~Example() { cout << "Example Destructor..." << endl; }

 int e;
};

int main() {

 shared_ptr<Example> pInt(new Example());
 cout << (*pInt).e << endl;
 cout << "pInt引用計數: " << pInt.use_count() << endl;

 shared_ptr<Example> pInt2 = pInt;
 cout << "pInt引用計數: " << pInt.use_count() << endl;
 cout << "pInt2引用計數: " << pInt2.use_count() << endl;
}

程式輸出如下:

Example Constructor...
pInt: 1
pInt引用計數: 1
pInt引用計數: 2
pInt2引用計數: 2
Example Destructor...

從上面這段程式碼中,我們對shared_ptr指標有了一些直觀的瞭解。

一方面,跟STL中大多數容器型別一樣,shared_ptr也是模板類,因此在建立shared_ptr時需要指定其指向的型別。

另一方面,正如其名一樣,shared_ptr指標允許讓多個該型別的指標共享同一堆分配物件。

同時shared_ptr使用經典的“引用計數”方法來管理物件資源,每個shared_ptr物件關聯一個共享的引用計數。

對於shared_ptr在拷貝和賦值時的行為,《C++Primer第五版》中有詳細的描述:

每個shared_ptr都有一個關聯的計數值,通常稱為引用計數。無論何時我們拷貝一個shared_ptr,計數器都會遞增。

例如,當用一個shared_ptr初始化另一個shred_ptr,或將它當做引數傳遞給一個函式以及作為函式的返回值時,它 所關聯的計數器就會遞增。

當我們給shared_ptr賦予一個新值或是shared_ptr被銷燬(例如一個區域性的 shared_ptr離開其作用域)時,計數器就會遞減。

一旦一個shared_ptr的計數器變為0,它就會自動釋放自己所管理 的物件。

對比我們上面的程式碼可以看到:當我們將一個指向Example物件的指標交給pInt管理後,其關聯的引用計數為1。

接下來,我們用pInt初始化pInt2,兩者關聯的引用計數值增加為2。隨後,函式結束,pInt和PInt2相繼離開函式作用於,相應的引用計數值分別自減1最後變為0,於是Example物件被自動釋放(呼叫其解構函式)。

接下來,我們完整地介紹一下shared_ptr的常見用法:

1、建立shared_ptr例項

最安全和高效的方法是呼叫make_shared庫函式,該函式會在堆中分配一個物件並初始化,最後返回指向此物件的share_ptr例項。

如果你不想使用make_ptr,也可以先明確new出一個物件,然後把其原始指標傳遞給share_ptr的建構函式。

示例如下:

int main() {

 // 傳遞給make_shared函式的引數必須和shared_ptr所指向型別的某個建構函式相匹配
 shared_ptr<string> pStr = make_shared<string>(10,'a');
 cout << *pStr << endl; // aaaaaaaaaa

 int *p = new int(5);
 shared_ptr<int> pInt(p);
 cout << *pInt << endl; // 5
}

2、訪問所指物件

shared_ptr的使用方式與普通指標的使用方式類似,既可以使用解引用操作符*獲得原始物件進而訪問其各個成員,也可以使用指標訪問符->來訪問原始物件的各個成員。

3、拷貝和賦值操作

我們可以用一個shared_ptr物件來初始化另一個share_ptr例項,該操作會增加其引用計數值。

例如:

int main() {
 shared_ptr<string> pStr = make_shared<string>(10,'a');
 cout << pStr.use_count() << endl; // 1

 shared_ptr<string> pStr2(pStr);
 cout << pStr.use_count() << endl; // 2
 cout << pStr2.use_count() << endl; // 2
}

如果shared_ptr例項p和另一個shared_ptr例項q所指向的型別相同或者可以相互轉換,我們還可以進行諸如p = q這樣賦值操作。

該操作會遞減p的引用計數值,遞增q的引用計數值。

例如:

class Example
{
public:
 Example(string n) : name(n) { cout << n << " constructor..." << endl; }
 ~Example() { cout << name << " destructor..." << endl; }

 string name;
};

int main() {

 shared_ptr<Example> pStr = make_shared<Example>("a object");
 shared_ptr<Example> pStr2 = make_shared<Example>("b object");
 cout << pStr.use_count() << endl;
 cout << pStr2.use_count() << endl;

 pStr = pStr2; // 此後pStr和pStr指向相同物件
 cout << pStr->name << endl;
 cout << pStr2->name << endl;
}

輸出如下:

a object constructor...
b object constructor...
1
1
a object destructor...
b object
b object
b object destructor...

4、檢查引用計數

shared_ptr提供了兩個函式來檢查其共享的引用計數值,分別是unique()和use_count()。

在前面,我們已經多次使用過use_count()函式,該函式返回當前指標的引用計數值。值得注意的是use_count()函式可能效率很低,應該只把它用於測試或除錯。

unique()函式用來測試該shared_ptr是否是原始指標唯一擁有者,也就是use_count()的返回值為1時返回true,否則返回false。

示例:

int main() {
 shared_ptr<string> pStr = make_shared<string>(10,'a');
 cout << pStr.unique() << endl; // true

 shared_ptr<string> pStr2(pStr);
 cout << pStr2.unique() << endl; // false;
}

總結

到此這篇關於C++11 智慧指標之shared_ptr程式碼詳解的文章就介紹到這了,更多相關 C++11 shared_ptr內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!