最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++智能指針模板應(yīng)用詳細(xì)介紹

 更新時(shí)間:2022年08月22日 09:08:44   作者:Shawn-Summer  
從比較簡(jiǎn)單的層面來(lái)看,智能指針是RAII(Resource Acquisition Is Initialization,資源獲取即初始化)機(jī)制對(duì)普通指針進(jìn)行的一層封裝。這樣使得智能指針的行為動(dòng)作像一個(gè)指針,本質(zhì)上卻是一個(gè)對(duì)象,這樣可以方便管理一個(gè)對(duì)象的生命周期

智能指針模板類

void remodel(std::string & str)
{
    std::string *ps =new std::string(str);
    ....
    if(oh_no)
        throw exception();
    ...
    delete ps;
    return;
}

如果上面這段函數(shù)出現(xiàn)異常,那么就會(huì)發(fā)生內(nèi)存泄漏。傳統(tǒng)指針在執(zhí)行動(dòng)態(tài)內(nèi)存分配時(shí)具有缺陷,很容易導(dǎo)致內(nèi)存泄漏。如果有一個(gè)指針,指針被釋放的同時(shí),它指向的內(nèi)存也能被釋放,那就完美了。這種指針就是智能指針。

我們只介紹3個(gè)智能指針模板類:auto_ptr、unique_ptr、shared_ptr,順便會(huì)提一下weak_ptr。其中auto_ptr已經(jīng)被拋棄了,它是一個(gè)過(guò)時(shí)的產(chǎn)物,我們介紹它只為拋磚引玉。

使用智能指針

這些智能指針模板定義了類似指針的對(duì)象,我們把new獲得的地址賦給這種對(duì)象,當(dāng)智能指針過(guò)期時(shí),它的析構(gòu)函數(shù)會(huì)自動(dòng)釋放動(dòng)態(tài)內(nèi)存。

必須包含頭文件memory,這個(gè)文件包含模板定義。我們使用模板實(shí)例化來(lái)創(chuàng)建所需指針.

類模板大概是:

template<class X>
class auto_ptr
{
public:
    explicit auto_ptr(X* p) noexcept;
    ....
}

所以我們實(shí)例化:

auto_ptr<double> pd(new double);或者auto_ptr<string> ps(new string);。

對(duì)于其他兩種智能指針也是一樣的構(gòu)造語(yǔ)法。

//智能指針1.cpp
#include<iostream>
#include<string>
#include<memory>
class Report
{
private:
    std::string str;
public:
    Report(const std::string &s):str(s){std::cout<<"Object created!\n";}
    ~Report(){std::cout<<"Object deleted";}
    void comment() const{std::cout<<str<<"\n";}
};
int main()
{
    {
        std::auto_ptr<Report> ps(new Report("using auto_ptr"));
        ps->comment();
    }
    {
        std::unique_ptr<Report> ps(new Report("using unique_ptr"));
        ps->comment();
    }
    {
        std::shared_ptr<Report> ps(new Report("using shared_ptr"));
        ps->comment();
    }
}

Object created!
using auto_ptr
Object deletedObject created!
using unique_ptr
Object deletedObject created!
using shared_ptr
Object deleted

注意,所有智能指針類都有一個(gè)explicit構(gòu)造函數(shù),該構(gòu)造函數(shù)將指針作為參數(shù)。所以它不會(huì)將指針轉(zhuǎn)換成智能指針對(duì)象。

shared_ptr<double> pd;
double *p_reg=new double;
pd=p_reg;//不允許因?yàn)闃?gòu)造函數(shù)是`explicit`修飾的,所以不能隱式類型轉(zhuǎn)換
pd=shared_ptr<double>(p_reg);//允許,使用賦值運(yùn)算符
shared_ptr<double> pshared=p_reg;//不允許,因?yàn)椴荒茈[式類型轉(zhuǎn)換
shared_ptr<double> pshared(p_reg);//允許調(diào)用構(gòu)造函數(shù)。

智能指針和傳統(tǒng)指針有很多類似的語(yǔ)法:例如可以使用*ps來(lái)解除引用,也可以使用ps->來(lái)訪問(wèn)結(jié)構(gòu)成員。

但是最重要的不同是:我們只能用能進(jìn)行delete或者delete[]的指針來(lái)構(gòu)造智能指針。

也就是說(shuō):

int a=5;
int *p=&a;
shared_ptr<int> ps(p);

上面這段代碼就是錯(cuò)誤的,因?yàn)?code>p無(wú)法使用delete.

#include<memory>
#include<iostream>
int main()
{
    using namespace std;
    /*{
        auto_ptr<int[]> ps(new int[2]{1,2});
        cout<<ps[0]<<endl;
        cout<<ps[1]<<endl;
    }*/
    {
        unique_ptr<int[]> ps(new int[2]{1,2});
        cout<<ps[0]<<endl;
        cout<<ps[1]<<endl;
    }
    {
        shared_ptr<int []> ps(new int[2]{1,2});
        cout<<ps[0]<<endl;
        cout<<ps[1]<<endl;
    }
}

上面代碼告訴我們,我們可以使用<int []>這樣實(shí)例化模板,這是為了模擬動(dòng)態(tài)數(shù)組。

關(guān)于智能指針的注意事項(xiàng)

auto_ptr<string> ps(new string("I reigned lonely as a cloud."));
auto_ptr<string> pd;
pd=ps;

上面這段代碼不會(huì)報(bào)錯(cuò),但是你可能會(huì)問(wèn):pd和ps都是智能指針,如果我們把ps賦給pd;那么就說(shuō)明這兩個(gè)指針指向同一個(gè)string對(duì)象,那么當(dāng)這兩個(gè)指針消失時(shí),會(huì)對(duì)同一個(gè)string對(duì)象釋放兩次?

我們看看我們?nèi)绾伪苊膺@種問(wèn)題:

  • 進(jìn)行深復(fù)制
  • 建立所有權(quán)概念,對(duì)于特定的對(duì)象,只能有一個(gè)智能指針擁有它,這樣就只有擁有它的智能指針的析構(gòu)函數(shù)才會(huì)釋放內(nèi)存。然后賦值運(yùn)算會(huì)轉(zhuǎn)讓所有權(quán)。auto_ptrunique_ptr都是使用這種策略,但是unique_ptr更嚴(yán)格。
  • 使用引用計(jì)數(shù),每個(gè)對(duì)象都會(huì)記錄有多少個(gè)智能指針指向它,然后賦值運(yùn)算時(shí),計(jì)數(shù)加1,指針過(guò)期時(shí)計(jì)數(shù)減1。當(dāng)最后一個(gè)指針過(guò)期時(shí),才會(huì)調(diào)用delete,這是shared_ptr的策略。

實(shí)際上,上述這些策略也適用于復(fù)制構(gòu)造函數(shù)。

實(shí)際上,unique_ptr就是"唯一指針",指針和被指向的對(duì)象一一對(duì)應(yīng),而shared_ptr就是"分享指針",它允許多個(gè)指針指向同一個(gè)對(duì)象。所以說(shuō),shared_ptr的用法更像C風(fēng)格指針。

我們看上面的代碼,pd=ps后,由于string對(duì)象的所有權(quán)交給了pd,所以*ps就無(wú)法使用了。

//智能指針3.cpp
#include<iostream>
#include<string>
#include<memory>
int main()
{
    using namespace std;
    auto_ptr<string> films[5]=
    {
        auto_ptr<string>(new string("1")),
        auto_ptr<string>(new string("2")),
        auto_ptr<string>(new string("3")),
        auto_ptr<string>(new string("4")),
        auto_ptr<string>(new string("5"))
    };
    auto_ptr<string> p;
    p=films[2];
    for(int i=0;i<5;i++)
    {
        cout<<*films[i]<<endl;
    }
    cout<<*p<<endl;
}

上面這段代碼會(huì)出錯(cuò),因?yàn)?code>p=films[2];使得,films[2]的所有權(quán)轉(zhuǎn)讓給p了,所以cout<<*film[2]就會(huì)出錯(cuò)。但是如果使用shared_ptr代替auto_ptr就可以正常運(yùn)行了。如果使用unique_ptr呢?程序會(huì)在編譯階段報(bào)錯(cuò),而不是在運(yùn)行階段報(bào)錯(cuò),所以說(shuō)unique_ptr更加嚴(yán)格。

unique_ptr優(yōu)于auto_ptr

首先就是上面談過(guò)的,unique_ptr的所有權(quán)概念比auto_ptr要嚴(yán)格,所以unique_ptr更加安全。

unique_ptr<string> ps(new string("I reigned lonely as a cloud."));
unique_ptr<string> pd;
pd=ps;

上述代碼會(huì)在編譯階段報(bào)錯(cuò),因?yàn)槌霈F(xiàn)了危險(xiǎn)的懸掛指針ps(即野指針,指針指向被刪除的內(nèi)存,如果使用野指針修改內(nèi)存是會(huì)造成嚴(yán)重后果)。

但是有時(shí)候?qū)⒁粋€(gè)智能指針賦給另一個(gè)并不會(huì)留下懸掛指針:

unique_ptr<string> demo(const char*s)
{
    unique_ptr<string> temp(new string(s));
    return temp;
}
...
unique_ptr<string>ps;
ps= demo("something");
...

demo()函數(shù)返回一個(gè)臨時(shí)變量temp,然后臨時(shí)變量temp被賦給ps,那么temp就變成懸掛指針了,但是我們知道ps=demo("something")一旦運(yùn)行結(jié)束,demo()里的所有局部變量都會(huì)消失包括temp。所以即使temp是野指針,我們也不會(huì)使用它。神奇的是,編譯器也允許上面這種賦值。

總之,程序試圖將一個(gè)unique_ptr賦給另一個(gè)時(shí),如果源unique_ptr是個(gè)臨時(shí)右值,編譯器允許這么做;如果源unique_ptr會(huì)存在一段世界,編譯器禁止這么做。

unique_ptr<string> pu1;
pu1=unique_ptr<string>(new string("yo!"));

上面這段代碼也是允許的,因?yàn)?code>unique_ptr<string>(new string("yo!"))是一個(gè)臨時(shí)右值(右值都是臨時(shí)的,右值只在當(dāng)前語(yǔ)句有效,語(yǔ)句結(jié)束后右值就會(huì)消失)

unique_ptr<string> ps(new string("I reigned lonely as a cloud."));
unique_ptr<string> pd;
pd=std::move(ps);

上面代碼是正確的,如果你想要進(jìn)行將unique_ptr左值,賦給unique_ptr左值,那么你必須使用move()函數(shù),這個(gè)函數(shù)會(huì)將左值轉(zhuǎn)換成右值。

以上所說(shuō),反映了一個(gè)事實(shí):unique_ptrauto_ptr安全。其實(shí)unique_ptr還有一個(gè)優(yōu)點(diǎn):auto_ptr的析構(gòu)函數(shù)只能使用delete,而unique_ptr的析構(gòu)函數(shù)可以使用delete[]delete

選擇智能指針

首先明確一個(gè)事實(shí):shared_ptr更方便;unique_ptr更安全。

如果程序需要適用多個(gè)指向同一個(gè)對(duì)象的指針,那么只能選擇shared_ptr;如果不需要多個(gè)指向同一個(gè)對(duì)象的指針,那么兩種指針都可以使用??傊?嫌麻煩的話就全部用shared_ptr.

#include<memory>
#include<iostream>
#include<vector>
#include<cstdlib>
#include<algorithm>
std::unique_ptr<int> make_int(int n)
{
    return std::unique_ptr<int>(new int(n));
}
void show(const std::unique_ptr<int> &pi)
{
    std::cout<<*pi<<' ';
}
int main()
{
    using std::vector;
    using std::unique_ptr;
    using std::rand;
    int size=10;
    vector<unique_ptr<int>> vp(size);
    for(int i=0;i<size;i++)
        vp[i]=make_int(rand()%1000);//#1
    vp.push_back(make_int(rand()%1000));//#2
    std::for_each(vp.begin(),vp.end(),show);//#3
}

上面這段代碼是使用unique_ptr寫的,#1.#2是沒有問(wèn)題的,因?yàn)楹瘮?shù)返回值是臨時(shí)右值,#3就要注意了.show()函數(shù)使用的是引用參數(shù),如果換成按值傳遞,那就會(huì)出錯(cuò),因?yàn)檫@會(huì)導(dǎo)致,使用unique_ptr左值初始化pi,這時(shí)不允許的,記得嗎?在使用unique_ptr時(shí),它的賦值運(yùn)算符要求:只能用右值賦給左值。(實(shí)際上,它的復(fù)制構(gòu)造函數(shù)也要求只接受右值)。

當(dāng)unique_ptr是右值的時(shí)候,我們可以把他賦給shared_ptr。

shared_ptr包含一個(gè)顯式構(gòu)造函數(shù),他會(huì)把右值unique_ptr轉(zhuǎn)換成shared_ptr:

unique_ptr<int> pup(make_int(rand()%1000));//ok
shared_ptr<int> spp(pup);//不允許,構(gòu)造函數(shù)不能接受`unique_ptr`的左值
shared_ptr<int> spr(make_int(rand()%1000));//ok

weak_ptr

weak_ptr正如它名字所言:一個(gè)虛弱的指針,一個(gè)不像是指的指針。weak_ptr是用來(lái)輔助shared_ptr的。

為什么說(shuō)weak_ptr不像指針呢?是因?yàn)樗鼪]有重載*[]運(yùn)算符。

通常,我們使用shared_ptr來(lái)初始化weak_ptr,那么這兩個(gè)指針都指向是同一塊動(dòng)態(tài)內(nèi)存。

weak_ptrshared_ptr的輔助,所以它幫忙能查看這塊動(dòng)態(tài)內(nèi)存的信息:包括引用計(jì)數(shù)、存的信息。

#include<memory>
#include<iostream>
int main()
{
    using std::shared_ptr;
    using std::weak_ptr;
    using std::cout;
    using std::endl;
    shared_ptr<int> p1(new int(255));
    weak_ptr<int>wp(p1);
    cout<<"引用計(jì)數(shù): "<<wp.use_count()<<endl;
    cout<<"存儲(chǔ)信息: "<<*(wp.lock())<<endl;
    shared_ptr<int> p2=p1;
    cout<<"引用計(jì)數(shù): "<<wp.use_count()<<endl;
    cout<<"存儲(chǔ)信息: "<<*(wp.lock())<<endl;
}

引用計(jì)數(shù): 1  
存儲(chǔ)信息: 255
引用計(jì)數(shù): 2  
存儲(chǔ)信息: 255

weak_ptr的類方法中use_count()查看指向和當(dāng)前weak_ptr指針相同的shared_ptr指針的數(shù)量,lock()函數(shù)返回一個(gè)和當(dāng)前weak_ptr指針指向相同的shared_ptr指針。

到此這篇關(guān)于C++智能指針模板應(yīng)用詳細(xì)介紹的文章就介紹到這了,更多相關(guān)C++智能指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談C#互操作的內(nèi)存溢出問(wèn)題

    淺談C#互操作的內(nèi)存溢出問(wèn)題

    以前了解過(guò)c++的棧內(nèi)存溢出,沒想到在c#里被我遇到了,問(wèn)題看似不大,如何被恰好相鄰的四個(gè)字節(jié)是返回地址,說(shuō)不定危害不小??!看來(lái)c#的互操作還是得小心為好
    2013-10-10
  • C++11 std::shared_ptr總結(jié)與使用示例代碼詳解

    C++11 std::shared_ptr總結(jié)與使用示例代碼詳解

    這篇文章主要介紹了C++11 std::shared_ptr總結(jié)與使用,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義

    C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義

    這篇文章主要介紹了C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-09-09
  • iOS鎖屏音頻播放控制及音頻信息設(shè)置

    iOS鎖屏音頻播放控制及音頻信息設(shè)置

    這篇文章主要為大家詳細(xì)介紹了iOS鎖屏音頻播放控制及音頻信息設(shè)置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • C++實(shí)現(xiàn)涂色游戲(博弈)

    C++實(shí)現(xiàn)涂色游戲(博弈)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)涂色游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • 使用C++一步步實(shí)現(xiàn)俄羅斯方塊

    使用C++一步步實(shí)現(xiàn)俄羅斯方塊

    本文給大家分享的是作者在使用C++制作俄羅斯方塊的時(shí)候的思路分析以及開發(fā)準(zhǔn)備和實(shí)驗(yàn)原理,都是些基礎(chǔ)的知識(shí)儲(chǔ)備,希望大家能夠喜歡,具體的代碼我們下一節(jié)再分享給大家
    2017-12-12
  • Cocos2d-x中背景音樂和音效使用實(shí)例

    Cocos2d-x中背景音樂和音效使用實(shí)例

    這篇文章主要介紹了Cocos2d-x中背景音樂和音效使用實(shí)例,注意本文中使用大量注釋來(lái)說(shuō)明背景音樂和音效的使用方法,需要的朋友可以參考下
    2014-09-09
  • C語(yǔ)言堆結(jié)構(gòu)處理TopK問(wèn)題詳解

    C語(yǔ)言堆結(jié)構(gòu)處理TopK問(wèn)題詳解

    TopK問(wèn)題即在N個(gè)數(shù)中找出最大的前K個(gè),這篇文章將詳細(xì)講解如何利用小根堆的方法解決TopK問(wèn)題,文中代碼具有一定參考價(jià)值,快跟隨小編一起學(xué)習(xí)一下吧
    2022-06-06
  • 基于C語(yǔ)言實(shí)現(xiàn)創(chuàng)意多彩貪吃蛇游戲

    基于C語(yǔ)言實(shí)現(xiàn)創(chuàng)意多彩貪吃蛇游戲

    這篇文章主要介紹了如何利用C語(yǔ)言實(shí)現(xiàn)一個(gè)創(chuàng)意多彩貪吃蛇游戲,這是一個(gè)純C語(yǔ)言外加easyx庫(kù)的繪圖函數(shù)制作而成的有趣小游戲,無(wú)需引入額外資源,感興趣的可以動(dòng)手嘗試一下
    2022-08-08
  • 一文詳解C++中的引用與關(guān)鍵字auto

    一文詳解C++中的引用與關(guān)鍵字auto

    引用就是給一個(gè)已經(jīng)存在的變量取一個(gè)別名,與變量共用一段內(nèi)存空間。關(guān)鍵字auto一般可以用來(lái)自動(dòng)識(shí)別類型,本文主要來(lái)講講二者的相關(guān)知識(shí),需要的可以參考一下
    2023-04-04

最新評(píng)論

灵丘县| 米易县| 台东市| 和田市| 湛江市| 红河县| 隆尧县| 洪洞县| 图们市| 古田县| 柳河县| 鄂托克前旗| 岳普湖县| 海伦市| 辽源市| 托里县| 山东| 华蓥市| 广东省| 五原县| 新竹市| 江津市| 肇州县| 岑巩县| 临沭县| 中西区| 大洼县| 那坡县| 平定县| 屏南县| 山丹县| 庐江县| 广州市| 白水县| 光泽县| 陕西省| 梁平县| 丹寨县| 曲麻莱县| 肥城市| 柘荣县|