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釋放資源。
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)使用方法
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;
#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";
}
#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)使用方法
3)用于函數(shù)的參數(shù)
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的線程安全性:
9)如果unique_ptr能解決問題,就不要用shared_ptr。unique_ptr的效率更高,占用的資源更少。
#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á)式,形參為原始指針。
#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_ptrshared_ptr內(nèi)部維護(hù)了一個共享的引用計數(shù)器,多個shared_ptr可以指向同一個資源。
如果出現(xiàn)了循環(huán)引用的情況,引用計數(shù)永遠(yuǎn)無法歸0,資源不會被釋放。
#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的助手而不是智能指針。
#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())是線程安全的。
#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;
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧