1. 程式人生 > >智能指針C++11

智能指針C++11

class coffee 工作 div .net cto default 操作 clu

(讀書筆記:全部摘抄自cPP標註庫)

C++ 11 中,標準庫提供了兩大類smart pointer:

1. Class shared_ptr 實現共享式擁有(shared ownership)概念。多個 只能指針 可以指向相同的對象,改對象和其相關資源會在 “最後一個reference被銷毀” 時釋放。為了在結構較為復雜的情境中執行上述工作,標準庫提供了weak_ptr ,bad_weak_ptr 和 enable_shared_from_this等輔助類。

2,Class_unique_ptr 實現獨占式擁有(exclusive ownership) 或 嚴格擁有(strict ownership)概念。保證同一時間內只有一個smart pointer可以指向該對象。你可以移交擁有權。他對於 避免資源泄露特別有用。

c++98只讓c++標準庫提供一個smart pointer class : auto_ptr<>,其設計是為了執行現今的unique_ptr所提供的服務。然而由於當時缺乏語言特性如“針對構造和賦值”的move語義,以及其他瑕疵,這個class不易被理解且容易出錯。因此在TR1引入clss shared_ptr,c++11引入class unique_ptr之後,auto_ptr成為c++11中被證實反對的成分,除非老舊代碼需要編譯,否則你不應使用它。

所有smart pointer class 都被定義於頭文件<memory>內。

shard_ptr 的目標是沒有蛀牙(在其所指向的對象不再被需要之後,自動釋放與對象相關的資源)。

使用shard_ptr

#include<iostream>
#include<string>
#include<vector>
#include<memory>

using namespace std;

int main(){
    shared_ptr<string> pNico(new string("nico"));
    shared_ptr<string> pJutta(new string("jutta"));

    (*pNico)[0] = N;
    pJutta->replace(0
,1,"J"); vector<shared_ptr<string>> whoMadeCoffee; whoMadeCoffee.push_back(pJutta); whoMadeCoffee.push_back(pJutta); whoMadeCoffee.push_back(pNico); whoMadeCoffee.push_back(pNico); for(auto ptr : whoMadeCoffee) { cout << *ptr << " "; } cout << endl; *pNico = " Nicolai"; for(auto ptr : whoMadeCoffee) { cout << *ptr << " "; } cout << endl; cout << "use_cout " << whoMadeCoffee[0].use_count() << endl; }

需要註意的是,由於“接受單一pointer作為唯一實參" 的構造函數是explicit,所以這裏不能使用賦值符,因為那樣的話會被視為需要一個隱式轉換,然而新式的語法是被接受的:

shared_ptr<string> pNico = new string("nico");  //ERROR
shared_ptr<string> pNico{new string("nico")};   //OK

也可以使用便捷的 make_shared() :

shared_ptr<string> pNico = make_shared<string>("nico");

這種方式比較快,也比較安全,因為它使用一次而非二次分配:一次針對對象,另一次針對"shared pointer 用以控制對象" 的shared data。

另一種寫法是,先聲明shard pointer ,然後對它賦值一個new pointer,然後不可以使用assignment操作符,必須改用reset():

pNico3 = new string("nico");    //ERROR :no assignment for ordinary pointers
pNico3.reset(new string("nico"));   //Ok

定義一個Deleter

定義一個deleter,例如讓它在“刪除被指向對象”之前先打印一條信息:

shared_ptr<string> pNico(new string("nico"),
                         [](string * p){
                             cout << "delete " << *p << endl;
                             delete p;
                         });
pNico = nullptr;  //pNico does not refer to string any longer
whoMadeCoffee.resize(2);   // all copies of string in pNico are destoryed                   

其中函數對象 D del參數是一個lambda表達式。

關於shared_ptr 的構造函數,參考鏈接

對付Array

shared_ptr提供的default deleter 調用的是delete,不是delete[] ,這意味著局限性,只有當shared_ptr擁有“由new建立起來的單一對象”,default deleter才試用。然而很不幸,為array建立一個shared_ptr是可能的,卻是錯誤的:

std::shared_ptr<int> p(new int[10]); //ERROR,but compiles

故,如果你試用new[]建立一個array of object ,必須自己定義自己deleter。你可以傳遞一個函數,或者函數對象,或者lambda,讓它們針對傳入的尋常指針調用delete[]。例如:

shared_ptr<int> p(new int[10],
                        [](int *p) {
                            delete[] p;
                        });

也可以試用為unique_ptr而提供的輔助函數作為deleter,其內調用deleter[]:

std::shared_ptr<int> p(new int[10], std::default_delete<int[]> ());

需要註意的是:shared_ptr 和unique_ptr 以稍稍不同的方式處理deleter。例如unique_ptr允許只傳遞對應的元素類型作為template實參,但這對shared_ptr就不行:

std::unique_ptr<int[]> p(new int[10]);  //OK
std::shared_ptr<int[]> p(new int[10]);  //ERROR:does not compile

此外,對於 unique_ptr,你必須明確給予第二個template實參,指出自己的deleter:

std::unique_ptr<int,void(*)(int *)> p(new int[10], [](int *p) {
                            delete[] p;
});                       

還需註意,shared_ptr不提供operator[]。至於unique_ptr,它有一個針對array的偏特化版本,該版本提供operator[] 取代 operator* 和 operator-> 。之所以有此差異是因為,unique_ptr在效能和彈性上進行了優化。

智能指針C++11