真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

C++11后的智能指針-創(chuàng)新互聯(lián)

文章目錄
  • 一、智能指針unique_ptr
    • 1.基本用法
    • 2.更多技巧
  • 二、智能指針shared_ptr
    • 1.基本用法
    • 2.更多細(xì)節(jié)
    • 3.智能指針的刪除器
    • 4.weak_ptr

創(chuàng)新互聯(lián)一直秉承“誠信做人,踏實做事”的原則,不欺瞞客戶,是我們最起碼的底線! 以服務(wù)為基礎(chǔ),以質(zhì)量求生存,以技術(shù)求發(fā)展,成交一個客戶多一個朋友!為您提供網(wǎng)站制作、成都做網(wǎng)站、成都網(wǎng)頁設(shè)計、微信小程序開發(fā)、成都網(wǎng)站開發(fā)、成都網(wǎng)站制作、成都軟件開發(fā)、成都App制作是成都本地專業(yè)的網(wǎng)站建設(shè)和網(wǎng)站設(shè)計公司,等你一起來見證!一、智能指針unique_ptr

unique_ptr獨享它指向的對象,也就是說,同時只有一個unique_ptr指向同一個對象,當(dāng)這個unique_ptr被銷毀時,指向的對象也隨即被銷毀。

包含頭文件:#includetemplate>class unique_ptr
{public:
	explicit unique_ptr(pointer p) noexcept;	// 不可用于轉(zhuǎn)換函數(shù)。
	~unique_ptr() noexcept;    
	T& operator*() const;            // 重載*操作符。
	T* operator->() const noexcept;  // 重載->操作符。
	unique_ptr(const unique_ptr &) = delete;   // 禁用拷貝構(gòu)造函數(shù)。
	unique_ptr& operator=(const unique_ptr &) = delete;  // 禁用賦值函數(shù)。
	unique_ptr(unique_ptr &&) noexcept;	  // 右值引用。
	unique_ptr& operator=(unique_ptr &&) noexcept;  // 右值引用。
	// ...
private:
	pointer ptr;  // 內(nèi)置的指針。
};

第一個模板參數(shù)T:指針指向的數(shù)據(jù)類型。
第二個模板參數(shù)D:指定刪除器,缺省用delete釋放資源。

1.基本用法
  • eg:測試類AA的定義:
class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string & name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< m_name<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
};

1)初始化

方法一:
unique_ptrp0(new AA("西施"));     // 分配內(nèi)存并初始化。

方法二:
unique_ptrp0 = make_unique("西施");   // C++14標(biāo)準(zhǔn)。
unique_ptrpp1=make_unique();         // 數(shù)據(jù)類型為int。
unique_ptrpp2 = make_unique();       // 數(shù)據(jù)類型為AA,默認(rèn)構(gòu)造函數(shù)。
unique_ptrpp3 = make_unique("西施");  // 數(shù)據(jù)類型為AA,一個參數(shù)的構(gòu)造函數(shù)。
unique_ptrpp4 = make_unique("西施",8); // 數(shù)據(jù)類型為AA,兩個參數(shù)的構(gòu)造函數(shù)。

方法三(不推薦):
AA* p = new AA("西施");
unique_ptrp0(p);                  // 用已存在的地址初始化。

2)使用方法

  • 智能指針重載了*和->操作符,可以像使用指針一樣使用unique_ptr。
  • 不支持普通的拷貝和賦值。
AA* p = new AA("西施");
	unique_ptrpu2 = p;              // 錯誤,不能把普通指針直接賦給智能指針。
	unique_ptrpu3 = new AA("西施"); // 錯誤,不能把普通指針直接賦給智能指針。
	unique_ptrpu2 = pu1;           // 錯誤,不能用其它unique_ptr拷貝構(gòu)造。
	unique_ptrpu3;
	pu3 = pu1;                            // 錯誤,不能用=對unique_ptr進(jìn)行賦值。
  • 不要用同一個裸指針初始化多個unique_ptr對象。

  • get()方法返回裸指針。

  • 不要用unique_ptr管理不是new分配的內(nèi)存。

  • 用于函數(shù)的參數(shù)
    傳引用(不能傳值,因為unique_ptr沒有拷貝構(gòu)造函數(shù))。
    裸指針。

4)不支持指針的運算(+、-、++、–)

2.更多技巧

1)將一個unique_ptr賦給另一個時,如果源unique_ptr是一個臨時右值,編譯器允許這樣做;如果源unique_ptr將存在一段時間,編譯器禁止這樣做。一般用于函數(shù)的返回值。

unique_ptrfunc()
{return unique_ptr(new int{100});	
}

unique_ptrUnPtr1 = func();//OK
unique_ptrUnPtr2;
UnPtr2=func();//OK

unique_ptrp0;
p0 = unique_ptr(new AA ("西瓜"));

2)用nullptr給unique_ptr賦值將釋放對象,空的unique_ptr==nullptr。

3)release()釋放對原始指針的控制權(quán),將unique_ptr置為空,返回裸指針。(可用于把unique_ptr傳遞給子函數(shù),子函數(shù)將負(fù)責(zé)釋放對象)

4)std::move()可以轉(zhuǎn)移對原始指針的控制權(quán)。(可用于把unique_ptr傳遞給子函數(shù),子函數(shù)形參也是unique_ptr)

5)reset()釋放對象。

void reset(T * _ptr= (T *) nullptr);
pp.reset();        // 釋放pp對象指向的資源對象。
pp.reset(nullptr);  // 釋放pp對象指向的資源對象
pp.reset(new AA("bbb"));  // 釋放pp指向的資源對象,同時指向新的對象。

6)swap()交換兩個unique_ptr的控制權(quán)。

void swap(unique_ptr&_Right);

7)unique_ptr也可象普通指針那樣,當(dāng)指向一個類繼承體系的基類對象時,也具有多態(tài)性質(zhì),如同使用裸指針管理基類對象和派生類對象那樣。

8)unique_ptr不是絕對安全,如果程序中調(diào)用exit()退出,全局的unique_ptr可以自動釋放,但局部的unique_ptr無法釋放。

unique_ptrptrGlobal = make_unique(100);//可以釋放

int main()
{unique_ptrptrlocal = make_unique(100);//無法釋放
	exit(0);
}

9)unique_ptr提供了支持?jǐn)?shù)組的具體化版本。

// unique_ptrparr1(new int[3]);          // 不指定初始值。
unique_ptrparr1(new int[3]{33,22,11 });  // 指定初始值。
cout<< "parr1[0]="<< parr1[0]<< endl;
cout<< "parr1[1]="<< parr1[1]<< endl;
cout<< "parr1[2]="<< parr1[2]<< endl;

unique_ptrparr2(new AA[3]{string("西施"), string("冰冰"), string("冪冪")});
cout<< "parr2[0].m_name="<< parr2[0].m_name<< endl;
cout<< "parr2[1].m_name="<< parr2[1].m_name<< endl;
cout<< "parr2[2].m_name="<< parr2[2].m_name<< endl;
  • eg1:
#include#includeusing  namespace std;

class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string & name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
};

// 函數(shù)func1()需要一個指針,但不對這個指針負(fù)責(zé)。
void func1(const AA* a) {cout<< a->m_name<< endl;
}

// 函數(shù)func2()需要一個指針,并且會對這個指針負(fù)責(zé)。
void func2(AA* a) {cout<< a->m_name<< endl;
	delete a;
}

// 函數(shù)func3()需要一個unique_ptr,不會對這個unique_ptr負(fù)責(zé)。
void func3(const unique_ptr&a) {cout<< a->m_name<< endl;
}

// 函數(shù)func4()需要一個unique_ptr,并且會對這個unique_ptr負(fù)責(zé)。
void func4(unique_ptra) {cout<< a->m_name<< endl;
}

int main()
{unique_ptrpu(new AA("西施"));

	cout<< "開始調(diào)用函數(shù)。\n";
	//func1(pu.get());        // 函數(shù)func1()需要一個指針,但不對這個指針負(fù)責(zé)。
	//func2(pu.release());  // 函數(shù)func2()需要一個指針,并且會對這個指針負(fù)責(zé)。
	//func3(pu);                // 函數(shù)func3()需要一個unique_ptr,不會對這個unique_ptr負(fù)責(zé)。
	func4(move(pu));     // 函數(shù)func4()需要一個unique_ptr,并且會對這個unique_ptr負(fù)責(zé)。
	cout<< "調(diào)用函數(shù)完成。\n";

	if (pu == nullptr) cout<< "pu是空指針。\n";
}
  • eg2:
#include#includeusing  namespace std;

class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string & name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
};

int main()
{//AA* parr1 = new AA[2];   // 普通指針數(shù)組。
	AA* parr1 = new AA[2]{ string("西施"), string("冰冰") };
	//parr1[0].m_name = "西施1";
	//cout<< "parr1[0].m_name="<< parr1[0].m_name<< endl;
	//parr1[1].m_name = "西施2";
	//cout<< "parr1[1].m_name="<< parr1[1].m_name<< endl;
	//delete [] parr1;
	
	unique_ptrparr2(new AA[2]);   // unique_ptr數(shù)組。
	//unique_ptr parr2(new AA[2]{ string("西施"), string("冰冰") });
	parr2[0].m_name = "西施1";
	cout<< "parr2[0].m_name="<< parr2[0].m_name<< endl;
	parr2[1].m_name = "西施2";
	cout<< "parr2[1].m_name="<< parr2[1].m_name<< endl;
}
二、智能指針shared_ptr 1.基本用法

shared_ptr的構(gòu)造函數(shù)也是explicit,但是,沒有刪除拷貝構(gòu)造函數(shù)和賦值函數(shù)。

1)初始化

方法一:
shared_ptrp0(new AA("西施"));     // 分配內(nèi)存并初始化。

方法二:
shared_ptrp0 = make_shared("西施");  // C++11標(biāo)準(zhǔn),效率更高。
shared_ptrpp1=make_shared();         // 數(shù)據(jù)類型為int。
shared_ptrpp2 = make_shared();       // 數(shù)據(jù)類型為AA,默認(rèn)構(gòu)造函數(shù)。
shared_ptrpp3 = make_shared("西施");  // 數(shù)據(jù)類型為AA,一個參數(shù)的構(gòu)造函數(shù)。
shared_ptrpp4 = make_shared("西施",8); // 數(shù)據(jù)類型為AA,兩個參數(shù)的構(gòu)造函數(shù)。

方法三:
AA* p = new AA("西施");
shared_ptrp0(p);                  // 用已存在的地址初始化。

方法四:
shared_ptrp0(new AA("西施")); 
shared_ptrp1(p0);                 // 用已存在的shared_ptr初始化,計數(shù)加1。
shared_ptrp1=p0;                 // 用已存在的shared_ptr初始化,計數(shù)加1。

2)使用方法

  • 智能指針重載了*和->操作符,可以像使用指針一樣使用shared_ptr。
  • use_count()方法返回引用計數(shù)器的值。
  • unique()方法,如果use_count()為1,返回true,否則返回false。
  • shared_ptr支持賦值,左值的shared_ptr的計數(shù)器將減1,右值shared_ptr的計算器將加1。
  • get()方法返回裸指針。
  • 不要用同一個裸指針初始化多個shared_ptr。
  • 不要用shared_ptr管理不是new分配的內(nèi)存。

3)用于函數(shù)的參數(shù)

  • 與unique_ptr的原理相同。

4)不支持指針的運算(+、-、++、–)

2.更多細(xì)節(jié)

1)用nullptr給shared_ptr賦值將把計數(shù)減1,如果計數(shù)為0,將釋放對象,空的shared_ptr==nullptr。

2)std::move()可以轉(zhuǎn)移對原始指針的控制權(quán)。還可以將unique_ptr轉(zhuǎn)移成shared_ptr。(反之不可以)

3)reset()改變與資源的關(guān)聯(lián)關(guān)系。

pp.reset();        // 解除與資源的關(guān)系,資源的引用計數(shù)減1。
pp. reset(new AA("bbb"));  // 解除與資源的關(guān)系,資源的引用計數(shù)減1。關(guān)聯(lián)新資源。

4)swap()交換兩個shared_ptr的控制權(quán)。

void swap(shared_ptr&_Right);

5)shared_ptr也可象普通指針那樣,當(dāng)指向一個類繼承體系的基類對象時,也具有多態(tài)性質(zhì),如同使用裸指針管理基類對象和派生類對象那樣。

6)shared_ptr不是絕對安全,如果程序中調(diào)用exit()退出,全局的shared_ptr可以自動釋放,但局部的shared_ptr無法釋放。

7)shared_ptr提供了支持?jǐn)?shù)組的具體化版本。

8)shared_ptr的線程安全性:

  • shared_ptr的引用計數(shù)本身是線程安全(引用計數(shù)是原子操作)。
  • 多個線程同時讀同一個shared_ptr對象是線程安全的。
  • 如果是多個線程對同一個shared_ptr對象進(jìn)行讀和寫,則需要加鎖。
  • 多線程讀寫shared_ptr所指向的同一個對象,不管是相同的shared_ptr對象,還是不同的shared_ptr對象,也需要加鎖保護(hù)。

9)如果unique_ptr能解決問題,就不要用shared_ptr。unique_ptr的效率更高,占用的資源更少。

  • eg:
#include#includeusing  namespace std;

class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string & name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
};

int main()
{shared_ptrpa0(new AA("西施a"));     // 初始化資源西施a。
	shared_ptrpa1 = pa0;                       // 用已存在的shared_ptr拷貝構(gòu)造,計數(shù)加1。
	shared_ptrpa2 = pa0;                       // 用已存在的shared_ptr拷貝構(gòu)造,計數(shù)加1。
	cout<< "pa0.use_count()="<< pa0.use_count()<< endl;   // 值為3。

	shared_ptrpb0(new AA("西施b"));    // 初始化資源西施b。
	shared_ptrpb1 = pb0;                      // 用已存在的shared_ptr拷貝構(gòu)造,計數(shù)加1。
	cout<< "pb0.use_count()="<< pb0.use_count()<< endl;   // 值為2。

	pb1 = pa1;      // 資源西施a的引用加1,資源西施b的引用減1。
	pb0 = pa1;      // 資源西施a的引用加1,資源西施b的引用成了0,將被釋放。

	cout<< "pa0.use_count()="<< pa0.use_count()<< endl;   // 值為5。
	cout<< "pb0.use_count()="<< pb0.use_count()<< endl;   // 值為5。
}
3.智能指針的刪除器

在默認(rèn)情況下,智能指針過期的時候,用delete原始指針; 釋放它管理的資源。
程序員可以自定義刪除器,改變智能指針釋放資源的行為。
刪除器可以是全局函數(shù)、仿函數(shù)和Lambda表達(dá)式,形參為原始指針。

  • eg:
#include#includeusing  namespace std;

class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string & name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
};

void deletefunc(AA* a) {// 刪除器,普通函數(shù)。
	cout<< "自定義刪除器(全局函數(shù))。\n";
	delete a;
}

struct deleteclass               // 刪除器,仿函數(shù)。
{void operator()(AA* a) {cout<< "自定義刪除器(仿函數(shù))。\n";
		delete a;
	}
};

auto deleterlamb = [](AA* a) {// 刪除器,Lambda表達(dá)式。
	cout<< "自定義刪除器(Lambda)。\n";
	delete a;
};

int main()
{shared_ptrpa1(new AA("西施a"), deletefunc);
	//shared_ptr pa2(new AA("西施b"), deleteclass());
	//shared_ptr pa3(new AA("西施c"), deleterlamb);
	
	//unique_ptr pu1(new AA("西施1"), deletefunc);
    // unique_ptr pu0(new AA("西施1"), deletefunc);
	//unique_ptr pu2(new AA("西施2"), deleteclass());
	//unique_ptr pu3(new AA("西施3"), deleterlamb);
}
4.weak_ptr

shared_ptr內(nèi)部維護(hù)了一個共享的引用計數(shù)器,多個shared_ptr可以指向同一個資源。
如果出現(xiàn)了循環(huán)引用的情況,引用計數(shù)永遠(yuǎn)無法歸0,資源不會被釋放。

  • eg:
#include#includeusing  namespace std;

class BB;

class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string & name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
	shared_ptrm_p;
};

class BB
{public:
	string m_name;
	BB() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)BB()。\n"; }
	BB(const string& name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)BB("<< m_name<< ")。\n"; }
	~BB() {cout<< "調(diào)用了析構(gòu)函數(shù)~BB("<< m_name<< ")。\n"; }
	shared_ptrm_p;
};

int main()
{shared_ptrpa = make_shared("西施a");
	shared_ptrpb = make_shared("西施b");
	
	pa->m_p = pb;
	pb->m_p = pa;
}

weak_ptr 是為了配合shared_ptr而引入的,它指向一個由shared_ptr管理的資源但不影響資源的生命周期。

也就是說,將一個weak_ptr綁定到一個shared_ptr不會改變shared_ptr的引用計數(shù)。

不論是否有weak_ptr指向,如果最后一個指向資源的shared_ptr被銷毀,資源就會被釋放。

weak_ptr更像是shared_ptr的助手而不是智能指針。

  • eg:
#include#includeusing  namespace std;

class BB;

class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string & name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
	weak_ptrm_p;
};

class BB
{public:
	string m_name;
	BB() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)BB()。\n"; }
	BB(const string& name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)BB("<< m_name<< ")。\n"; }
	~BB() {cout<< "調(diào)用了析構(gòu)函數(shù)~BB("<< m_name<< ")。\n"; }
	weak_ptrm_p;
};

int main()
{shared_ptrpa = make_shared("西施a");
	shared_ptrpb = make_shared("西施b");
	
	cout<< "pa.use_count()="<< pa.use_count()<< endl;
	cout<< "pb.use_count()="<< pb.use_count()<< endl;

	pa->m_p = pb;
	pb->m_p = pa;

	cout<< "pa.use_count()="<< pa.use_count()<< endl;
	cout<< "pb.use_count()="<< pb.use_count()<< endl;
}

如何使用weak_ptr ?
weak_ptr沒有重載 ->和 *操作符,不能直接訪問資源。
有以下成員函數(shù):

1)operator=();  // 把shared_ptr或weak_ptr賦值給weak_ptr。
2)expired();     // 判斷它指資源是否已過期(已經(jīng)被銷毀)。
3)lock();        // 返回shared_ptr,如果資源已過期,返回空的shared_ptr。
4)reset();       // 將當(dāng)前weak_ptr指針置為空。
5)swap();       // 交換。

weak_ptr不控制對象的生命周期,但是,它知道對象是否還活著。
用lock()函數(shù)把它可以提升為shared_ptr,如果對象還活著,返回有效的shared_ptr,如果對象已經(jīng)死了,提升會失敗,返回一個空的shared_ptr。
提升的行為(lock())是線程安全的。

  • eg:
#include#includeusing  namespace std;

class BB;

class AA
{public:
	string m_name;
	AA() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)AA()。\n"; }
	AA(const string& name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)AA("<< m_name<< ")。\n"; }
	~AA() {cout<< "調(diào)用了析構(gòu)函數(shù)~AA("<< m_name<< ")。\n"; }
	weak_ptrm_p;
};

class BB
{public:
	string m_name;
	BB() {cout<< m_name<< "調(diào)用構(gòu)造函數(shù)BB()。\n"; }
	BB(const string& name) : m_name(name) {cout<< "調(diào)用構(gòu)造函數(shù)BB("<< m_name<< ")。\n"; }
	~BB() {cout<< "調(diào)用了析構(gòu)函數(shù)~BB("<< m_name<< ")。\n"; }
	weak_ptrm_p;
};

int main()
{shared_ptrpa = make_shared("西施a");

	{shared_ptrpb = make_shared("西施b");

		pa->m_p = pb;
		pb->m_p = pa;

		shared_ptrpp = pa->m_p.lock();            // 把weak_ptr提升為shared_ptr。
		if (pp == nullptr)
			cout<< "語句塊內(nèi)部:pa->m_p已過期。\n";
		else
			cout<< "語句塊內(nèi)部:pp->m_name="<< pp->m_name<< endl;
	}

	shared_ptrpp = pa->m_p.lock();            // 把weak_ptr提升為shared_ptr。
	if (pp == nullptr)
		cout<< "語句塊外部:pa->m_p已過期。\n";
	else
		cout<< "語句塊外部:pp->m_name="<< pp->m_name<< endl;
}
  • ref:鏈接

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧


標(biāo)題名稱:C++11后的智能指針-創(chuàng)新互聯(lián)
當(dāng)前網(wǎng)址:http://weahome.cn/article/djcssg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部