欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報(bào)激活碼778899分享:開發(fā)語言 【C++】share

柚子快報(bào)激活碼778899分享:開發(fā)語言 【C++】share

http://yzkb.51969.com/

一、share_ptr 的簡單使用

1.1、基本用法

從較淺的層面看,智能指針是利用了一種叫做RAII(資源獲取即初始化)的技術(shù)對普通的指針進(jìn)行封裝,這使得智能指針實(shí)質(zhì)是一個(gè)對象,行為表現(xiàn)的卻像一個(gè)指針。

智能指針的作用是防止忘記調(diào)用delete釋放內(nèi)存和程序異常的進(jìn)入catch塊忘記釋放內(nèi)存。另外指針的釋放時(shí)機(jī)也是非常有考究的,多次釋放同一個(gè)指針會(huì)造成程序崩潰,這些都可以通過智能指針來解決。

智能指針的行為類似于一個(gè)常規(guī)指針,與常規(guī)指針之間重要的區(qū)別就是它負(fù)責(zé)自動(dòng)釋放所管理的資源,share_ptr 使用引用計(jì)數(shù),允許多個(gè) share_ptr 指向同一資源,每多一個(gè) share_ptr 指向該資源,share_ptr 的引用計(jì)數(shù)就 +1 ,減為0時(shí)表示沒有 share_ptr 對該資源進(jìn)行引用了,就會(huì)釋放所指向的資源。share_ptr 內(nèi)部中的引用計(jì)數(shù)是線程安全的,但是引用的資源不是線程安全的。

1.2、初始化?

裸指針直接初始化,但不能通過隱式轉(zhuǎn)換來構(gòu)造,因?yàn)?share_ptr 構(gòu)造函數(shù)被聲明為 explicit允許移動(dòng)構(gòu)造與拷貝構(gòu)造通過 make_share 構(gòu)造

#include

#include

class test {};

int main()

{

std::shared_ptr f(new test()); // 裸指針直接初始化

//std::shared_ptr f1 = new test(); // Error,explicit禁止隱式初始化

std::shared_ptr f2(f); // 拷貝構(gòu)造函數(shù)

std::shared_ptr f3 = f; // 拷貝構(gòu)造函數(shù)

f2 = f; // copy賦值運(yùn)算符重載

std::cout << f3.use_count() << " " << f3.unique() << std::endl;

std::shared_ptr f4(std::move(new test())); // 移動(dòng)構(gòu)造函數(shù)

//std::shared_ptr f5 = std::move(new test()); // Error,explicit禁止隱式初始化

std::shared_ptr f6(std::move(f4)); // 移動(dòng)構(gòu)造函數(shù)

std::shared_ptr f7 = std::move(f6); // 移動(dòng)構(gòu)造函數(shù)

std::cout << f7.use_count() << " " << f7.unique() << std::endl;

std::shared_ptr f8(new test[10]()); // Error,管理動(dòng)態(tài)數(shù)組時(shí),需要指定刪除器

std::shared_ptr f9(new test[10](), std::default_delete());

auto f10 = std::make_shared(); // std::make_shared來創(chuàng)建

return 0;

}

在初始化上 share_ptr 與 unique_ptr 在初始化上的方式就有區(qū)別,二者都不支持隱式初始化,但是 unque_ptr 不支持拷貝構(gòu)造和拷貝賦值,而 share_ptr 則都支持。

1.3、刪除器

刪除器可以是普通函數(shù)、函數(shù)對象和 lambda 表達(dá)式等,默認(rèn)的刪除器為 std::default_delete ,內(nèi)部是使用 delete 來實(shí)現(xiàn)的,與 unique_ptr 不同,刪除器不是 share_ptr 類型的組成部分,也就是說兩個(gè) sptr1,sptr2 有不同的刪除器,但只要它們的類型是相同的都可以被放入同一容器中。此外,在動(dòng)態(tài)管理數(shù)組的時(shí)候,share_ptr 需要指定刪除器。智能指針的大小與被引用的資源的大小是無關(guān)的,因?yàn)橹悄苤羔樖且彩峭ㄟ^指針來對該資源進(jìn)行訪問,而不是存儲(chǔ)在智能指針內(nèi)部。

#include

#include

#include

class Frame {};

int main()

{

auto del1 = [](Frame* f){

std::cout << "delete1" << std::endl;

delete f;

};

auto del2 = [](Frame* f){

std::cout << "delete2" << std::endl;

delete f;

};

std::shared_ptr f1(new Frame(), del1);

std::shared_ptr f2(new Frame(), del2);

std::unique_ptr f3(new Frame(), del);

std::vector > v;

v.push_back(f1);

v.push_back(f2);

return 0;

}

二、剖析 share_ptr

2.1、share_ptr 的內(nèi)存模型

share_ptr 的內(nèi)存模型長這樣(直接使用的陳碩大神的圖)

將其簡化只剩下引用計(jì)數(shù)與原始指針后長這樣:

從圖中我們可以看出,share_ptr 包含了一個(gè)指向?qū)ο蟮闹羔樅鸵粋€(gè)指向控制塊的指針。每一個(gè)由share_ptr 管理的對象都有一個(gè)控制塊,除了包含強(qiáng)引用計(jì)數(shù)、弱引用技術(shù)之外,還包含了自定義刪除器的副本和分配器的副本以及其他附加數(shù)據(jù)。

2.2、控制塊的創(chuàng)建規(guī)則

std::make_shared 總是創(chuàng)建一個(gè)控制塊從具備所有權(quán)的指針觸發(fā)構(gòu)造一個(gè) share_ptr 的時(shí)候,會(huì)創(chuàng)建一個(gè)控制塊(比如 unique_ptr 在轉(zhuǎn)換成 share_ptr 的時(shí)候會(huì)創(chuàng)建控制塊,因?yàn)?unique_ptr 本身不使用控制塊,同時(shí) unique_ptr 置空)當(dāng) share_ptr 構(gòu)造函數(shù)使用裸指針作為實(shí)參時(shí),會(huì)創(chuàng)建一個(gè)控制塊(也就是說,從同一個(gè)裸指針出發(fā)構(gòu)造多個(gè) share_ptr 的時(shí)候會(huì)創(chuàng)建多個(gè)控制塊,這也就意味著裸指針可能會(huì)被釋放多次。如果想從一個(gè)已經(jīng)擁有控制塊的對象出發(fā)創(chuàng)建一個(gè) share_ptr ,此時(shí)我們就可以傳遞一個(gè) share_ptr 或 weak_ptr 而非裸指針作為構(gòu)造函數(shù)的參數(shù),這樣就不會(huì)創(chuàng)建新的控制器)

因此,盡可能避免將裸指針傳遞給 share_ptr 的一個(gè)有效的辦法是 make_shared。如果必須將一個(gè)裸指針作為參數(shù)傳入到 share_ptr 的構(gòu)造函數(shù),就直接傳遞 new 運(yùn)算符運(yùn)算的結(jié)果而非傳遞一個(gè)裸指針。

2.3、盡量使用 make 函數(shù)

make_shared 內(nèi)部是通過調(diào)用 allocate_shared 來進(jìn)行實(shí)現(xiàn)的,與 new 相比,make 系列函數(shù)的優(yōu)勢:避免代碼冗余,創(chuàng)建智能指針的時(shí)候,被創(chuàng)建的對象只需要寫一次,如 make_shared,而用 new 來進(jìn)行創(chuàng)建智能指針的時(shí)候需要寫兩次。異常安全性,make 系列函數(shù)可編寫異常安全代碼,增強(qiáng)了安全性

使用 make 函數(shù)與使用 new 進(jìn)行構(gòu)造的 share_ptr 內(nèi)存布局如下:

make 系列函數(shù)的局限性:

所有的 make 系列函數(shù)都不允許自定義刪除器make 系列函數(shù)創(chuàng)建對象時(shí),不能接受{}初始化列表(這是因?yàn)橥昝擂D(zhuǎn)發(fā)的轉(zhuǎn)發(fā)函數(shù)是一個(gè)模板函數(shù),利用模板類型進(jìn)行推導(dǎo)。因此無法把{}推導(dǎo)為 initializer_list)也就是說,make 系列只能將圓括號(hào)內(nèi)的參數(shù)進(jìn)行轉(zhuǎn)發(fā)自定義內(nèi)存管理的類(如重載了 operator new 和 operator delete)不建議使用 make_shared 來創(chuàng)建,因?yàn)橹剌d?operator new 和 operator delete 時(shí),往往用來分配和釋放該類精確尺寸的內(nèi)存塊,而 make_shared 創(chuàng)建的 shared_ptr,是一個(gè)自定義了分配器 (allocate_shared) 和刪除器的智能指針,由 allocate_shared 分配的內(nèi)存大小也不等于上述的尺寸,而是在此基礎(chǔ)上加上控制塊的大小對象的內(nèi)存可能無法及時(shí)回收。因?yàn)椋簃ake_shared 只分配一次內(nèi)存,減少了內(nèi)存分配的開銷,使得控制塊和托管對象在同一內(nèi)存塊上分配。而控制塊是由 shared_ptr 和 weak_ptr 共享的,因此兩者共同管理著這個(gè)內(nèi)存塊(托管對象 + 控制塊)。當(dāng)強(qiáng)引用計(jì)數(shù)為 0 時(shí),托管對象被析構(gòu)(即析構(gòu)函數(shù)被調(diào)用),但內(nèi)存塊并未被回收,只有等到最后一個(gè) weak_ptr 離開作用域時(shí),弱引用也減為 0 才會(huì)釋放這塊內(nèi)存塊。原本強(qiáng)引用減為 0 時(shí)就可以釋放的內(nèi)存, 現(xiàn)在變?yōu)榱藦?qiáng)引用和弱引用都減為 0 時(shí)才能釋放, 意外的延遲了內(nèi)存釋放的時(shí)間。這對于內(nèi)存要求高的場景來說,是一個(gè)需要注意的問題。

2.4、引用計(jì)數(shù)

shared_ptr 中的引用計(jì)數(shù)直接關(guān)系到何時(shí)是否進(jìn)行對象的析構(gòu),因此它的變動(dòng)變得尤為重要shared_ptr 的構(gòu)造函數(shù)會(huì)使該引用計(jì)數(shù)遞增,而析構(gòu)函數(shù)則會(huì)使得引用計(jì)數(shù)遞減。但移動(dòng)構(gòu)造表示從一個(gè)已有的 shared_ptr 移動(dòng)構(gòu)造到另一個(gè)新的 shared_ptr ,這意味著一旦新的 shared_ptr 產(chǎn)生后,原有的 shared_ptr 就會(huì)被置空,結(jié)果就是引用計(jì)數(shù)沒有變化??截愘x值構(gòu)造同時(shí)執(zhí)行兩種操作如(例如 p1 和 p2 是指向不同對象的 shared_ptr ,則執(zhí)行? ? ? ? ?p1 = p1 時(shí),將修改 p1 使得其指向 p2 所值的對象,而最初 p1 所指向的對象的引用計(jì)數(shù)遞減,同時(shí) p2 所指向的對象引用計(jì)數(shù)遞增 )reset 函數(shù),如果不帶參數(shù)時(shí),則引用計(jì)數(shù)減 1。如果帶參數(shù)時(shí),如 sp.reset(p) 則 sp 原來指向的對象引用計(jì)數(shù)減 1 ,同時(shí) sp 指向新的對象 p。如果實(shí)施一次遞減后,最后的引用計(jì)數(shù)變?yōu)?0 ,即不再有 shared_ptr 指向該對象,則會(huì)被 shared_ptr 析構(gòu)掉。

需要注意的是:引用計(jì)數(shù)本身是安全且無鎖的,但對象的讀寫則不是。

2.5、this 返回 shared_ptr?

不要將 this 指針返回給 shared_ptr。當(dāng)希望將 this 指針托管給 shared_ptr 時(shí),類需要繼承自? ? ? ? ? std::enable_shared_from_this ,并且從 shared_from_this() 中獲得 shared_ptr 指針。

#include

#include

class Frame {

public:

std::shared_ptr GetThis() {

return std::shared_ptr(this);

}

};

int main()

{

std::shared_ptr f1(new Frame());

std::shared_ptr f2 = f1->GetThis();

std::cout << f1.use_count() << " " << f2.use_count() << std::endl;

std::shared_ptr f3(new Frame());

std::shared_ptr f4 = f3;

std::cout << f3.use_count() << " " << f4.use_count() << std::endl;

return 0;

}

運(yùn)行結(jié)果:

此時(shí)就很奇怪,GetThis() 返回的不是 f1 本身嘛?而為什么 f2 和 f4 的結(jié)果就有這樣的區(qū)別呢?

其實(shí),直接從 this 指針創(chuàng)建,會(huì)為 this 對象創(chuàng)建新的控制塊,也就相當(dāng)于從裸指針重新創(chuàng)建一個(gè)新的控制塊。

為了解決這個(gè)問題,標(biāo)準(zhǔn)庫提供了解決方法:讓類派生于一個(gè)模板類:enable_shared_from_this,然后調(diào)用 shared_from_this 函數(shù)即可

通過調(diào)用 shared_from_this 成員函數(shù)獲得一個(gè)和this指針指向相同對象的shared_ptr。

class Frame : public std::enable_shared_from_this {

public:

std::shared_ptr GetThis() {

return shared_from_this();

}

};

原理:

template

class enable_shared_from_this

{

protected:

constexpr enable_shared_from_this() noexcept { }

enable_shared_from_this(const enable_shared_from_this&) noexcept { }

enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept { return *this; }

~enable_shared_from_this() { }

public:

shared_ptr<_Tp> shared_from_this()

{ return shared_ptr<_Tp>(this->_M_weak_this); }

shared_ptr shared_from_this() const

{ return shared_ptr(this->_M_weak_this); }

private:

template

void _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept

{ _M_weak_this._M_assign(__p, __n); }

template

friend void __enable_shared_from_this_helper(const __shared_count<>&,

const enable_shared_from_this<_Tp1>*,

const _Tp2*) noexcept;

mutable weak_ptr<_Tp> _M_weak_this;

};

可以看到 enable_shared_from_this 模板類提供兩個(gè) public 屬性的 shared_from_this 成員函數(shù)。這兩個(gè)成員函數(shù)內(nèi)部會(huì)通過 _M_weak_this 成員來創(chuàng)建 shared_ptr 。其中 _M_weak_assign 函數(shù)不能手動(dòng)調(diào)用,這個(gè)函數(shù)會(huì)被 shared_ptr 自動(dòng)調(diào)用,用處是來初始化唯一的成員變量 _M_weak_this 。

分析:根據(jù)對象生成順序,先初始化基類 enable_shared_from_this ,再初始化派生類 Frame 對象本身,這時(shí) Frame 對象已經(jīng)生成,但 _M_weak_this 成員還未被初始化,最后應(yīng)通過 shared_ptr sp(new T()) 等方式調(diào)用 shared_ptr 構(gòu)造函數(shù)(內(nèi)部會(huì)調(diào)用 _M_weak_assign 成員函數(shù)來初始化 _M_weak_this 成員)。而如果在調(diào)用 shared_from_this 函數(shù)之前 weak_this_ 成員未被初始化,則會(huì)通過 ASSERT 報(bào)錯(cuò)顯示。

更深層次:這個(gè) enable_shared_from_this 中有一個(gè)弱指針 weak_ptr ,這個(gè)弱指針能夠監(jiān)視 this 指針,在調(diào)用 shared_from_this 這個(gè)函數(shù)時(shí),這個(gè)函數(shù)內(nèi)部實(shí)際上是調(diào)用 weak_ptr 的 lock 方法,lock() 會(huì)讓 shared_ptr 指針計(jì)數(shù) +1,同時(shí)返回這個(gè) shared_ptr。

參考:

第21課 shared_ptr共享型智能指針 - 淺墨濃香 - 博客園 (cnblogs.com)

【C++】shared_ptr共享型智能指針詳解-CSDN博客

柚子快報(bào)激活碼778899分享:開發(fā)語言 【C++】share

http://yzkb.51969.com/

相關(guān)文章

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19225284.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄