長久以來 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...