C++ 智能指針

一.簡介

C++的入門坑點大家都是有目共睹的,無非就是指針的理解不深導致一些野指針,內存泄露等問題,所以就不贅述。智能指針正好能夠彌補這些問題,因爲它本質是存放在棧的模板對象,只是在棧內部包了一層指針。而棧在其生命週期結束時,其中的指針指向的堆內存也自然被釋放了。因而實現了智能管理的效果,不需要考慮內存問題了,其實有點類似某種單例寫法,程序運行結束,也不用考慮單例對象內存問題。

c++11之前的auto_ptr; c++11新加的unique_ptr, shared_ptr以及weak_ptr。

包含頭文件 #include <memory>

在C++11中,引入了智能指針。主要有:unique_ptr, shared_ptr, weak_ptr。
這3種指針組件就是採用了boost裏的智能指針方案。很多有用過boost智能指針的朋友,很容易地就能發現它們之間的關間。

std boost 功能說明
unique_ptr scoped_ptr 獨佔指針對象,並保證指針所指對象生命週期與其一致
shared_ptr shared_ptr 可共享指針對象,可以賦值給shared_ptr或weak_ptr。
指針所指對象在所有的相關聯的shared_ptr生命週期結束時結束,是強引用。
weak_ptr weak_ptr 它不能決定所指對象的生命週期,引用所指對象時,需要lock()成shared_ptr才能使用。

 二.auto_ptr

auto_ptr是標準庫裏的智能指針,存在許多缺陷。 

//常用一些方法

1.get():返回當前指針對象

2.release():清空當前智能指針對象,並返回類型指針。所以假如我們要正常刪除,那麼需要這樣:

Base1*base2 = base1.release();
delete base2;

 3.reset():重置智能指針,即把內存刪除,且智能指針指向空,但類型不變,所以可以這樣安全便捷地刪除:

base1.reset();

4.auto_ptr還重載了等號操作符

auto_ptr <Base1> base2;

//將base1的控制權轉交給base2,且base1清空了
base2 = base1;

因此這樣就有些問題,控制權可以隨便轉換,但是隻有一個在用,用起來會受到諸多限制。

三.unique_ptr

unique_ptr 由 C++11 引入,旨在替代不安全的 auto_ptr,它持有對對象的獨有權——兩個unique_ptr不能指向一個對象,即 unique_ptr 不共享它所管理的對象。unique_ptr不支持普通的拷貝或賦值操作。只能移動 unique_ptr,即對資源管理權限可以實現轉移。

雖然我們不能拷貝或者賦值unique_ptr,但是可以通過調用release或reset將指針所有權從一個(非const)unique_ptr轉移給另一個unique_ptr。

move函數可以是用於構造函數,也可以用於賦值函數,但需要手動顯示添加,move函數用直白點的話來說就是省去拷貝構造和賦值時中間的臨時對象,將資源的內存從一個對象移動到(共享也可以)另一個對象。

//將所有權從p1轉移給p2,將p1置爲空
unique_ptr<string> p2(p1.release());

//將所有權從p3轉移到p2,reset釋放了p2原來指向的內存
unique_ptr<string>p3(new string("Trex"));
p2.reset(p3.release());

//base1變成empty
unique_ptr<Base1>	base1(new Base1);
unique_ptr<Base1>	base2 = move(base1);

//base2變成empty
unique_ptr<Base1>	base3;
base3 = move(base2);

 四.shared_ptr

 shared_ptr 是一個標準的共享所有權的智能指針,允許多個指針指向同一個對象;可以直接賦值和調用拷貝構造函數,且不會清空原本的智能指針。

 

 

//最安全的分配和使用動態內存的方法就是調用一個名爲make_shared的標準庫函數,此函數在動態內存中分配一個對象並初始化它,返回指向此對象的shared_ptr。
shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10,'9');
shared_ptr<int> p5 = make_shared<int>();

shared_ptr<Base1>	base1(new Base1);
shared_ptr<Base1>	base2 = base1;
shared_ptr<Base1>	base3;
base3 = base2;//三個共享一個

當刪除一個智能指針時,並不影響其它兩個智能指針的繼續使用。因爲該片內存添加了一個引用計數,每shared_ptr一次,引用計數+1;每次調用析構函數,引用計數減一。直到最後一個智能指針刪除,纔會釋放內存。 

shared_ptr和unique_ptr一樣可以通過move來切換控制權,這個時候是切換,不是共享了。auto_ptr和unique_ptr都可以通過move函數轉換成shared_ptr類型,當然,一樣是切換控制權的形式,即舊的置空。

auto_ptr<Base1>	     base1(new Base1);
shared_ptr<Base1>	 base2=move(base1);

五.weak_ptr

weak_ptr 被設計爲與 shared_ptr 共同工作,可以從一個 shared_ptr 或者另一個 weak_ptr 對象構造而來。weak_ptr 是爲了配合 shared_ptr 而引入的一種智能指針,它更像是 shared_ptr 的一個助手而不是智能指針,因爲它不具有普通指針的行爲,沒有重載 operator* 和 operator-> ,因此取名爲 weak,表明其是功能較弱的智能指針。它的最大作用在於協助 shared_ptr 工作,可獲得資源的觀測權,像旁觀者那樣觀測資源的使用情況。觀察者意味着 weak_ptr 只對 shared_ptr 進行引用,而不改變其引用計數,當被觀察的 shared_ptr 失效後,相應的 weak_ptr 也相應失效。
 

 

#include < assert.h>

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

int main()
{
	shared_ptr<int> sp(new int(10));
	assert(sp.use_count() == 1);

    //從shared_ptr創建weak_ptr
	weak_ptr<int> wp(sp); 	
	assert(wp.use_count() == 1);

    //判斷weak_ptr觀察的對象是否失效
	if (!wp.expired())		
	{
		shared_ptr<int> sp2 = wp.lock();//獲得一個shared_ptr
		*sp2 = 100;
		assert(wp.use_count() == 2);
	}
	assert(wp.use_count() == 1);
	cout << "int:" << *sp << endl;
    return 0;
}

從上面可以看到,儘管以 shared_ptr 來構造 weak_ptr,但是 weak_ptr內部的引用計數並沒有什麼變化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章