C 中的智慧型指標

2021-08-07 17:10:18 字數 4453 閱讀 2012

長久以來 c++ 最被人詬病的就是它的記憶體管理,寫個稍微複雜點的程式就經常會碰到記憶體洩漏問題。為了解決這個問題,c++ 也做了許多努力。

在 c++98 標準中首先提出了智慧型指標的概念,引入了 auto_ptr。但是在實踐中,auto_ptr 有不少問題。因此在 c++11 標準中對原有的智慧型指標又做了進一步的公升級,根據應用場景的不同,分成了 shared_ptr, weak_ptr, unique_ptr 三個智慧型指標類。

本文就來介紹一下這些指標類。

c++11 中引入的幾個智慧型指標的宣告在 memory 中。因此要使用智慧型指標需要包含這個標頭檔案。

#include
unique_ptr 顧名思義它具有某種唯一性。這種智慧型指標不共享它內部的指標。無法複製到其他 unique_ptr,無法通過值傳遞到函式。但是可以通過 c++11 中新引入的移動語義移動給另乙個 unique_ptr,當然移動之後它本身內部指標所對應的記憶體資源就轉移出去了,它自己就變成了乙個空指標了。

下面是乙個最簡單的例子,演示了兩種初始化 unique_ptr 智慧型指標的方法。

struct b 

virtual ~b()

};int main()

getchar();

}

執行的結果如下:

b::bar

b::~b

b::~b

可以看到,兩個 b 的例項都自動的呼叫了析構函式,因此我們就不需要自己去 delete 了。

下面再用乙個簡單的例子演示一下移動語義。

int main()

getchar();

}

執行結果如下:

b::bar

before move

b::~b

after move

b::~b

可以看到 p1 move 給 p2 後,p2 原先指向的物件就被析構掉了,同時 p1 擁有的物件也轉移了。這之後 p1 就是空指標了。

使用 unique_ptr 並不會影響 c++ 對多型的支援。比如下面這個例子:

struct b 

virtual ~b()

};struct d : b

~d()

void bar() override

};int main()

getchar();

}

執行結果如下:

d::d

d::bar

before move

b::~b

after move

d::~d

b::~b

下面來演示一下通過函式傳遞 unique_ptr 的方法:

std:

:unique_ptr pass_through(std:

:unique_ptr p)

int main()

getchar();

}

執行的結果如下:

d::d

d::bar

d::bar

d::~d

b::~b

我們知道派生類的指標可以賦值給基類指標。unique_ptr 也支援這麼做。比如下面的**片段:

std:

:unique_ptr p1 = std:

:make_unique(); // p is a unique_ptr that owns a d

std:

:unique_ptr p2 = std:

:move(p1);

但是如果反著寫就無法編譯了:

std:

:unique_ptr p1 = std:

:make_unique();

std:

:unique_ptr p2 = std:

:move(p1);

unique_ptr 可以放到容器中,下面是例子:

int main()

getchar();

}

執行結果如下:

d::d

d::d

d::bar

b::bar

d::bar

d::~d

b::~b

b::~b

d::~d

b::~b

unique_ptr 還支援new 多個物件,比如下面的**:

int main()

; p[1].bar();

}getchar();

}

執行結果如下:

d::d

d::d

d::d

d::bar

d::~d

b::~b

d::~d

b::~b

d::~d

b::~b

上面的例子中,unique_ptr 指向的記憶體都是在 unique_ptr 離開作用域時釋放的。但是有時我們需要提前釋放,這時就可以用 reset() 方法。比如 p 是個 unique_ptr,那麼 p.reset() 就釋放了 p 中指向的記憶體資源。

另乙個常用的函式是 swap,這個可以交換兩個 unique_ptr,比如下面的例子:

struct b 

virtual

void bar()

virtual ~b()

char c;

};int main()

getchar();

}

執行結果如下:

b::bar, c =1

b::bar, c =2

b::~b

b::~b

至此,unique_ptr 的基本用法就介紹完了,下面給出 unique_ptr 兩種形式,分別對應 new 和 new。

template

<

class t,

class deleter = std::default_delete> class unique_ptr;

template

<

class t,

class deleter

> class unique_ptr;

可以看到,我們還留下個 deleter 沒有介紹,這個 deleter 通常是用 lambda 表示式來實現的。有興趣的同學可以下面的**來學習:

可以說,unique_ptr 是用來取代 c++98 的 auto_ptr。在程式**中,遇到指標的地方,首選 unique_ptr,當 unique_ptr 不滿足需求時才考慮下面這兩種智慧型指標。

這種指標允許多個 shared_ptr 擁有同乙個記憶體資源。shared_ptr 內部維持著對擁有的記憶體資源的引用計數。比如有 5個 shared_ptr 擁有同乙個記憶體資源,那麼這個引用計數就是 5。這時如果乙個 shared_ptr 離開了它的作用域,那麼就還剩下 4 個 shared_ptr 擁有這個記憶體資源,引用計數就變為了 4。 當引用計數下降到 0 時,這個記憶體資源就被釋放了。

下面是個簡單的例子,給出了使用 shared_ptr 的基本方法:

using

namespace

std;

int main()

getchar();

}

結果如下:

s1

s22

weak_ptr 並不具備指標的全部功能,比如因為它沒有過載 operator* 和 ->,所以不能直接訪問記憶體資源,但是 weak_ptr 可以轉化為 shared_ptr,之後就能訪問資源了。我們可以認為 weak_ptr 是一種用來輔助 shared_ptr 的輔助類。

weak_ptr 對物件是弱引用,不會增加物件的引用計數,shared_ptr 可以直接賦值給它,它可以通過呼叫 lock 函式來獲得 shared_ptr。

這個指標相對來說不是那麼常用,所以就不多介紹了。

下面給個例子,介紹 weak_ptr 和 shared_ptr 的轉換:

#include 

#include

std::weak_ptr gw;

void f()

else

}int main()

f();

}

執行結果如下:

use_count == 1: 42

use_count == 0: gw is expired

c 中的智慧型指標

1.智慧型指標的作用 為了防止記憶體洩露的問題 c 程式設計中使用堆記憶體是非常頻繁的操作,堆記憶體的申請和釋放都由程式設計師自己管理。程式設計師自己管理堆記憶體可以提高了程式的效率,但是整體來說堆記憶體的管理是麻煩的,c 11中引入了智慧型指標的概念,方便管理堆記憶體。使用普通指標,容易造成堆記憶...

C 中的智慧型指標

c 中的四個智慧型指標分別是 1.shared ptr 2.unique ptr 3.weak ptr 4.auto ptr 已經被c 11棄用 在c 11的環境中會爆警告warning auto ptr is deprecated 智慧型指標的作用是管理乙個指標。因為存在以下這種情況 申請的空間在...

c 智慧型指標

auto prt 它是 它所指向物件的擁有者 所以當自身物件被摧毀時候,該物件也將遭受摧毀,要求乙個物件只有乙個擁有者,注意 auto prt 不能使用new 來分配物件給他 include include using namespace std template void bad print au...