最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

智能指針的源碼原來這么好讀(shared_ptr,weak_ptr)

2021-10-01 16:33 作者:NewtonCY  | 我要投稿

看了幾篇別人寫得文章,感覺寫得模模糊糊的。。于是自己去讀了讀。

本文不僅精確而且完備??戳吮疚闹?,即使自己實現(xiàn)一套智能指針也沒有問題。

1、先定義數(shù)據(jù)

下文中

  • “智能指針”指shared_ptr或weak_ptr

  • “裸指針”指原始的C指針

  • 裸指針還是智能指針通常是上下文自明的,此時直接用“指針”一詞指代兩者之一

首先,我們來看shared_ptr和weak_ptr持有了哪些數(shù)據(jù)。

對于shared_ptr和weak_ptr,都僅持有兩個字段,指向?qū)ο蟮刂返闹羔?strong>ptr,和指向計數(shù)器對象的指針rep。

對于計數(shù)器對象,我們僅需要關(guān)心兩個字段,一個是弱引用計數(shù)weaks(無符號整型),一個是強引用計數(shù)uses(無符號整型)。

那么,若s1,s2是僅有的兩個指向?qū)ο髈bj的shared_ptr,w1,w2,w3是僅有的三個指向?qū)ο髈bj的weak_ptr,則以上所有的智能指針(s1,s2,w1,w2,w3)的ptr字段保存著obj的地址,所有的rep字段指向同一個計數(shù)器對象(記為c1),c1的weaks字段現(xiàn)在是4(3+1,為什么加一后面會講),uses字段現(xiàn)在是2。

此時,為了我寫著方便,我們可以將s1和c1簡記為? ?s1=(&obj,&c1);c1=(u:2,w:4)

指針中兩個字段:ptr,rep。計數(shù)對象中兩個字段:uses,weaks。請捋順之后再向下閱讀。

2.再定義算法

下面,我們來結(jié)合例子來講每個操作背后發(fā)生了什么,注意:例子是連續(xù)的,即上一個操作的結(jié)束是下一個操作的開始。

操作1:構(gòu)造新的空指針

shared_ptr<int> s1,s2;

weak_ptr<int> w1;

初始化操作十分簡單,s1,s2和w1的ptr和rep都被初始為了NULL,

記作s1=s2=w1=(NULL,NULL)

操作2:使用裸指針構(gòu)造智能指針

int* a=new int(1);

int* b= new int(2);

s1.reset(a);??

發(fā)生條件:用裸指針reset智能指針,或?qū)⒙阒羔樧鳛閰?shù)調(diào)用構(gòu)造函數(shù)

執(zhí)行過程:

//創(chuàng)建一個新的計數(shù)器對象(記為c1),計數(shù)器對象的weaks和uses都初始為1

new c1=(u:1,w:1);?

// 將s1的ptr賦值為裸指針a,將s1的rep指向c1

s1=(a,&c1);??

操作3:從強引用構(gòu)造智能指針

s2=s1;? ?// uses計數(shù)+1

w1=s1;? // weaks計數(shù)+1

weak_ptr<int> w2(w1); //?weaks計數(shù)+1

發(fā)生條件:用shared_ptr構(gòu)造智能指針或賦值空的智能指針。用weak_ptr構(gòu)造weak_ptr或賦值空的weak_ptr。

執(zhí)行過程:

// 若右值的rep非空,則復(fù)制右值的rep到左值,然后將rep的uses或weaks計數(shù)原子+1

if(s1.rep&&s1.rep->uses或weaks計數(shù)原子+1)

????s2.rep = s1.rep;

s2.ptr=s1.ptr;

結(jié)果:

c1=(u:2,w:3);s1=s2=w1=w2=(a,&c1)

以下結(jié)論始終成立:

uses計數(shù)=實際強引用數(shù)。

weaks計數(shù)=

1.實際弱引用數(shù)+1(當(dāng)uses計數(shù)不為0)

2.實際弱引用數(shù)(當(dāng)uses計數(shù)為0)

如果uses計數(shù)不為0,則weaks計數(shù)至少為1


操作4:從弱引用構(gòu)造強引用

shared_ptr<int> s3(w1)

發(fā)生條件:用weak_ptr,構(gòu)造或賦值空的shared_ptr。執(zhí)行weak_ptr的lock函數(shù)

執(zhí)行過程:

if(w1.rep){

????將w1.rep->uses字段加樂觀鎖{

????????if(w1.rep->uses!=0){

????????????w1.rep->uses++;

????????????s3.rep=w1.rep;

????????????s3.ptr=w1.ptr;

????????}else{

????????????拋出bad_weak_ptr異常

????????}

????}

}

結(jié)果:

c1=(u:3,w:3);s1=s2=s3=w1=w2=(a,&c1)

操作5:釋放弱引用

w1.reset()

發(fā)生條件:1.對weak_ptr做reset。2.見“一些組合操作”

執(zhí)行過程:

w1.ptr=NULL;

w1.rep=NULL;

if(w1.rep->原子操作weaks-1并返回新的值 ==0){

????釋放對象 w1.rep;

}

操作6:釋放強引用

s1.reset()

發(fā)生條件:1.對shared_ptr做reset。2.見“一些組合操作”

執(zhí)行過程:

s1.ptr=NULL

s1.rep=NULL

f(s1.rep->原子操作uses-1并返回新的值 ==0){

? ? 對s1的rep額外執(zhí)行一次釋放弱引用操作;

????釋放對象s1.ptr;

}

// 如果uses為0,weaks計數(shù)等于實際弱引用數(shù),如果uses不為0,weaks計數(shù)等于實際弱引用數(shù)+1。因此如果users不為0則weaks至少為1。

操作7:一些組合操作和例子

此時,s2=s3=w2=(a,&c1); c1=(u:2,w:2)

操作:s2.reset(b);

相當(dāng)于執(zhí)行“強引用釋放操作”:?s2.reset(),然后再執(zhí)行“從裸指針初始化”操作? s2.reset(b)

操作完成后,此時:

s3=w2=(a,&c1); c1=(u:1,w:2); s2=(b,&c2);c2=(u:1,w:1)


操作:s3=s2

相當(dāng)于執(zhí)行“強引用釋放操作”:?s3.reset(),然后執(zhí)行“從強引用構(gòu)造智能指針”操作:s3=s2

此時

w2=(a,&c1); c1=(u:0,w:1);s1=s2=(b,&c2);c2=(u:2,w:1)

注意:s3.reset()的過程中,因為c1的uses減為0。所以 delete a操作被執(zhí)行,c1的weaks被額外-1。此時w2的ptr值依然等于指針a,但是delete a已經(jīng)被執(zhí)行,所以ptr=a是個野指針。但我們不會訪問到這個野指針,因為“從弱引用構(gòu)造強引用”這個操作會檢查uses的計數(shù),并拋出bad_weak_ptr異常。


操作:w2.reset()

這個操作是釋放弱引用。舉這個例子是想說,c1的weaks計數(shù)只剩下1了,此時執(zhí)行這個操作將使c1的weaks計數(shù)減為0并釋放c1。也標(biāo)志著所有指向a的強/弱引用全部釋放完畢。正如我反復(fù)強調(diào)的一樣,如果uses不為0,即強引用不為0,則weaks計數(shù)至少為1。weaks為0則強弱引用的數(shù)量必然都為0。

另外,考慮一種情況。設(shè)此時有 w1=(a,&c1); c1=(u:0,w:1);w2=(NULL,NULL)?

如果一個線程p1執(zhí)行w1.reset() 。同時線程p2執(zhí)行w2=w1

這是不安全的??紤]下面這種執(zhí)行順序

p2: w2=w1? ?執(zhí)行至? 檢查完成w1的rep非空,但是尚未執(zhí)行引用計數(shù)的增加。

p1:w1.reset() 完全執(zhí)行,此時weaks計數(shù)歸0,w1將rep所指向的c1釋放。

p2:w2=w1? ? 繼續(xù)執(zhí)行。它將使用野指針w1.rep執(zhí)行引用計數(shù)+1操作,并復(fù)制野指針rep和ptr。

當(dāng)p1線程寫w1時,p2讀了w1。這是犯規(guī)的。智能指針的線程安全性僅限于:

  1. 多線程持有不同的智能指針對象,此時并發(fā)的操作這些對象是線程安全的。即使他們引用的計數(shù)器對象是同一個。

  2. 多線程并發(fā)的讀同一個智能指針對象是安全的。

  3. 當(dāng)一個線程正在修改一個智能指針對象時,其他線程對這個智能指針進(jìn)行讀和寫都是不安全的。

主要操作的執(zhí)行過程就講完了。


3.分析它在并發(fā)下的正確性

寫累了。。累死了。。。有人看再寫

智能指針的源碼原來這么好讀(shared_ptr,weak_ptr)的評論 (共 條)

分享到微博請遵守國家法律
扎鲁特旗| 兴仁县| 桓台县| 连州市| 屏山县| 西林县| 武强县| 临潭县| 那坡县| 阳山县| 舞阳县| 尤溪县| 台中市| 江油市| 邳州市| 应城市| 永吉县| 灵寿县| 松桃| 睢宁县| 德昌县| 刚察县| 滦南县| 庆元县| 格尔木市| 拜城县| 霍城县| 吉木乃县| 曲阳县| 稷山县| 和硕县| 雷波县| 东莞市| 留坝县| 德江县| 肇庆市| 宁津县| 通化市| 香港| 香河县| 新闻|