91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++智能指針模板怎么應用

發布時間:2022-08-23 17:55:12 來源:億速云 閱讀:145 作者:iii 欄目:開發技術

本篇內容介紹了“C++智能指針模板怎么應用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

智能指針模板類

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

如果上面這段函數出現異常,那么就會發生內存泄漏。傳統指針在執行動態內存分配時具有缺陷,很容易導致內存泄漏。如果有一個指針,指針被釋放的同時,它指向的內存也能被釋放,那就完美了。這種指針就是智能指針。

我們只介紹3個智能指針模板類:auto_ptrunique_ptrshared_ptr,順便會提一下weak_ptr。其中auto_ptr已經被拋棄了,它是一個過時的產物,我們介紹它只為拋磚引玉。

使用智能指針

這些智能指針模板定義了類似指針的對象,我們把new獲得的地址賦給這種對象,當智能指針過期時,它的析構函數會自動釋放動態內存。

必須包含頭文件memory,這個文件包含模板定義。我們使用模板實例化來創建所需指針.

類模板大概是:

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

所以我們實例化:

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

對于其他兩種智能指針也是一樣的構造語法。

//智能指針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

注意,所有智能指針類都有一個explicit構造函數,該構造函數將指針作為參數。所以它不會將指針轉換成智能指針對象。

shared_ptr<double> pd;
double *p_reg=new double;
pd=p_reg;//不允許因為構造函數是`explicit`修飾的,所以不能隱式類型轉換
pd=shared_ptr<double>(p_reg);//允許,使用賦值運算符
shared_ptr<double> pshared=p_reg;//不允許,因為不能隱式類型轉換
shared_ptr<double> pshared(p_reg);//允許調用構造函數。

智能指針和傳統指針有很多類似的語法:例如可以使用*ps來解除引用,也可以使用ps->來訪問結構成員。

但是最重要的不同是:我們只能用能進行delete或者delete[]的指針來構造智能指針。

也就是說:

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

上面這段代碼就是錯誤的,因為p無法使用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 []>這樣實例化模板,這是為了模擬動態數組。

關于智能指針的注意事項

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

上面這段代碼不會報錯,但是你可能會問:pd和ps都是智能指針,如果我們把ps賦給pd;那么就說明這兩個指針指向同一個string對象,那么當這兩個指針消失時,會對同一個string對象釋放兩次?

我們看看我們如何避免這種問題:

  • 進行深復制

  • 建立所有權概念,對于特定的對象,只能有一個智能指針擁有它,這樣就只有擁有它的智能指針的析構函數才會釋放內存。然后賦值運算會轉讓所有權。auto_ptrunique_ptr都是使用這種策略,但是unique_ptr更嚴格。

  • 使用引用計數,每個對象都會記錄有多少個智能指針指向它,然后賦值運算時,計數加1,指針過期時計數減1。當最后一個指針過期時,才會調用delete,這是shared_ptr的策略。

實際上,上述這些策略也適用于復制構造函數。

實際上,unique_ptr就是"唯一指針",指針和被指向的對象一一對應,而shared_ptr就是"分享指針",它允許多個指針指向同一個對象。所以說,shared_ptr的用法更像C風格指針。

我們看上面的代碼,pd=ps后,由于string對象的所有權交給了pd,所以*ps就無法使用了。

//智能指針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;
}

上面這段代碼會出錯,因為p=films[2];使得,films[2]的所有權轉讓給p了,所以cout<<*film[2]就會出錯。但是如果使用shared_ptr代替auto_ptr就可以正常運行了。如果使用unique_ptr呢?程序會在編譯階段報錯,而不是在運行階段報錯,所以說unique_ptr更加嚴格。

unique_ptr優于auto_ptr

首先就是上面談過的,unique_ptr的所有權概念比auto_ptr要嚴格,所以unique_ptr更加安全。

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

上述代碼會在編譯階段報錯,因為出現了危險的懸掛指針ps(即野指針,指針指向被刪除的內存,如果使用野指針修改內存是會造成嚴重后果)。

但是有時候將一個智能指針賦給另一個并不會留下懸掛指針:

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

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

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

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

上面這段代碼也是允許的,因為unique_ptr<string>(new string("yo!"))是一個臨時右值(右值都是臨時的,右值只在當前語句有效,語句結束后右值就會消失)

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

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

以上所說,反映了一個事實:unique_ptrauto_ptr安全。其實unique_ptr還有一個優點:auto_ptr的析構函數只能使用delete,而unique_ptr的析構函數可以使用delete[]delete

選擇智能指針

首先明確一個事實:shared_ptr更方便;unique_ptr更安全。

如果程序需要適用多個指向同一個對象的指針,那么只能選擇shared_ptr;如果不需要多個指向同一個對象的指針,那么兩種指針都可以使用。總之,嫌麻煩的話就全部用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是沒有問題的,因為函數返回值是臨時右值,#3就要注意了.show()函數使用的是引用參數,如果換成按值傳遞,那就會出錯,因為這會導致,使用unique_ptr左值初始化pi,這時不允許的,記得嗎?在使用unique_ptr時,它的賦值運算符要求:只能用右值賦給左值。(實際上,它的復制構造函數也要求只接受右值)。

unique_ptr是右值的時候,我們可以把他賦給shared_ptr

shared_ptr包含一個顯式構造函數,他會把右值unique_ptr轉換成shared_ptr:

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

weak_ptr

weak_ptr正如它名字所言:一個虛弱的指針,一個不像是指的指針。weak_ptr是用來輔助shared_ptr的。

為什么說weak_ptr不像指針呢?是因為它沒有重載*[]運算符。

通常,我們使用shared_ptr來初始化weak_ptr,那么這兩個指針都指向是同一塊動態內存。

weak_ptrshared_ptr的輔助,所以它幫忙能查看這塊動態內存的信息:包括引用計數、存的信息。

#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<<"引用計數: "<<wp.use_count()<<endl;
    cout<<"存儲信息: "<<*(wp.lock())<<endl;
    shared_ptr<int> p2=p1;
    cout<<"引用計數: "<<wp.use_count()<<endl;
    cout<<"存儲信息: "<<*(wp.lock())<<endl;
}

引用計數: 1  
存儲信息: 255
引用計數: 2  
存儲信息: 255

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

“C++智能指針模板怎么應用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

湘西| 苍南县| 荆门市| 通河县| 方山县| 藁城市| 神木县| 张家港市| 印江| 新乡县| 绍兴市| 内黄县| 凌云县| 尖扎县| 政和县| 陆丰市| 钟山县| 安康市| 犍为县| 琼结县| 保靖县| 衡南县| 威海市| 阳信县| 富锦市| 阳曲县| 白山市| 页游| 巴南区| 龙南县| 探索| 德保县| 北川| 安陆市| 庆城县| 西平县| 临夏市| 四平市| 南川市| 罗江县| 巫溪县|