c 11 新特性 智慧型指標使用詳解

2021-10-19 05:23:38 字數 4122 閱讀 7328

c++11新增了新的智慧型指標,unique_ptr、shared_ptr和weak_ptr,同時也將auto_ptr置為廢棄(deprecated)。

但是在實際的使用過程中,很多人都會有這樣的問題:

不知道三種智慧型指標的具體使用場景

無腦只使用shared_ptr

認為應該禁用raw pointer(裸指標,即widget*這種形式),全部使用智慧型指標

初始化方法12

3456

78910

1112

1314

1516

1718

1920

2122

2324

class a

a(){}

void show()

private:

int size = 5;

};...

//[1]

auto p1 = std::make_shared();

auto p2 = std::make_shared();

//[2]

std::shared_ptrp3(new int(5));

std::shared_ptrp4(new a());

//[3]

std::shared_ptrp5;

p5.reset(new int(5));

std::shared_ptrp6;

p6.reset(new a());

推薦使用第一種方法~

使用場景

unique_ptr

忘記delete12

3456

78910

11class box

~box()

private:

widget* w;

};異常安全12

3456

void process()

shared_ptr

shared_ptr通常使用在共享權不明的場景。有可能多個物件同時管理同乙個記憶體時。

物件的延遲銷毀。陳碩在《linux多執行緒伺服器端程式設計》中提到,當乙個物件的析構非常耗時,甚至影響到了關鍵執行緒的速度。可以使用blockingqueue>將物件轉移到另外乙個執行緒中釋放,從而解放關鍵執行緒。

weak_ptr

weak_ptr是為了解決shared_ptr雙向引用的問題。即:12

3456

78910

11class b;

struct a;

struct b;

auto pa = make_shared();

auto pb = make_shared();

pa->b = pb;

pb->a = pa;

pa和pb存在著迴圈引用,根據shared_ptr引用計數的原理,pa和pb都無法被正常的釋放。

對於這種情況, 我們可以使用weak_ptr:12

3456

78910

11class b;

struct a;

struct b;

auto pa = make_shared();

auto pb = make_shared();

pa->b = pb;

pb->a = pa;

weak_ptr不會增加引用計數,因此可以打破shared_ptr的迴圈引用。

通常做法是parent類持有child的shared_ptr, child持有指向parent的weak_ptr。這樣也更符合語義。

效能1.unique_ptr

因為c++的zero cost abstraction的特點,unique_ptr在預設情況下和裸指標的大小是一樣的。

所以記憶體上沒有任何的額外消耗,效能是最優的。

2.shared_ptr

存占用高 shared_ptr的記憶體占用是裸指標的兩倍。因為除了要管理乙個裸指標外,還要維護乙個引用計數。 因此相比於unique_ptr, shared_ptr的記憶體占用更高

原子操作效能低 考慮到執行緒安全問題,引用計數的增減必須是原子操作。而原子操作一般情況下都比非原子操作慢。

使用移動優化效能 shared_ptr在效能上固然是低於unique_ptr。而通常情況,我們也可以盡量避免shared_ptr複製。 如果,乙個shared_ptr需要將所有權共享給另外乙個新的shared_ptr,而我們確定在之後的**中都不再使用這個shared_ptr,那麼這是乙個非常鮮明的移動語義。 對於此種場景,我們盡量使用std::move,將shared_ptr轉移給新的物件。因為移動不用增加引用計數,因此效能比複製更好。

物件所有權

首先需要理清楚的概念就是物件所有權的概念。所有權在rust語言中非常嚴格,寫rust的時候必須要清楚自己建立的每個物件的所有權。

但是c++比較自由,似乎我們不需要明白物件的所有權,寫的**也能正常執行。但是明白了物件所有權,我們才可以正確管理好物件生命週期和記憶體問題。

c++引入了智慧型指標,也是為了更好的描述物件所有權,簡化記憶體管理,從而大大減少我們c++記憶體管理方面的犯錯機會。

unique_ptr

我們大多數場景下用到的應該都是unique_ptr。

unique_ptr代表的是專屬所有權,即由unique_ptr管理的記憶體,只能被乙個物件持有。

所以,unique_ptr不支援複製和賦值,如下:12

auto w = std::make_unique();

auto w2 = w; // 編譯錯誤

如果想要把w複製給w2, 是不可以的。因為複製從語義上來說,兩個物件將共享同一塊記憶體。

因此,unique_ptr只支援移動, 即如下:12

auto w = std::make_unique();

auto w2 = std::move(w); // w2獲得記憶體所有權,w此時等於nullptr

unique_ptr代表的是專屬所有權,如果想要把乙個unique_ptr的記憶體交給另外乙個unique_ptr物件管理。只能使用std::move轉移當前物件的所有權。轉移之後,當前物件不再持有此記憶體,新的物件將獲得專屬所有權。

如上**中,將w物件的所有權轉移給w2後,w此時等於nullptr,而w2獲得了專屬所有權。

shared_ptr

在使用shared_ptr之前應該考慮,是否真的需要使用shared_ptr, 而非unique_ptr。

shared_ptr代表的是共享所有權,即多個shared_ptr可以共享同一塊記憶體。

因此,從語義上來看,shared_ptr是支援複製的。如下:12

3456

auto w = std::make_shared();

cout << w.use_count() << endl; // 1

shared_ptr內部是利用引用計數來實現記憶體的自動管理,每當複製乙個shared_ptr,引用計數會+1。當乙個shared_ptr離開作用域時,引用計數會-1。當引用計數為0的時候,則delete記憶體。

同時,shared_ptr也支援移動。從語義上來看,移動指的是所有權的傳遞。如下:12

auto w = std::make_shared();

auto w2 = std::move(w); // 此時w等於nullptr,w2.use_count()等於1

我們將w物件move給w2,意味著w放棄了對記憶體的所有權和管理,此時w物件等於nullptr。

而w2獲得了物件所有權,但因為此時w已不再持有物件,因此w2的引用計數為1。

指標作為函式傳參

只在函式使用指標,但並不儲存

假如我們只需要在函式中,用這個物件處理一些事情,但不打算涉及其生命週期的管理,不打算通過函式傳參延長shared_ptr的生命週期。

對於這種情況,可以使用raw pointer或者const shared_ptr&。即:1

2void func(widget*);

void func(const shared_ptr&)

​ 實際上第一種裸指標的方式可能更好,從語義上更加清楚,函式也不用關心智慧型指標的型別。

在函式中儲存智慧型指標

假如我們需要在函式中把這個智慧型指標儲存起來,這個時候建議直接傳值。void func(std::shared_ptr ptr);這樣的話,外部傳過來值的時候,可以選擇move或者賦值。函式內部直接把這個物件通過move的方式儲存起來。 這樣效能更好,而且外部呼叫也有多種選擇。

C 11新特性之智慧型指標

這一節將從用法上 記憶體儲存上以及生存週期上,對unique ptr,shared ptr和weak ptr做乙個深入剖析。unique ptr 不共享它的指標。它無法複製到其他 unique ptr,無法通過值傳遞到函式,也無法用於需要副本的任何標準模板庫 stl 演算法。只能移動 unique ...

詳解C 11智慧型指標

目錄 詳解c 11智慧型指標 前言 c 11智慧型指標介紹 為什麼要使用智慧型指標 auto ptr unique ptr shared ptr weak ptr 有些c 特性並沒有帶來實際上效能的提公升,而且還要花很多的時間來學習,導致我一段時間並不看好智慧型指標,因為普通指標用的很習慣了。但是看...

C 面試 C 11 新特性之智慧型指標

shared ptr 基本用法 shared ptr 採用引用計數的方式管理所指向的物件 當有乙個新的shared ptr指向同乙個物件時 複製shared ptr等 引用計數加1。當shared ptr離開作用域時,引用計數減1。當引用計數為0時,釋放所管理的記憶體。這樣做的好處在於解放了程式設計...