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

C++智能指針詳解

 更新時間:2022年08月17日 17:13:20   作者:頑張先生  
從比較簡單的層面來看,智能指針是RAII(Resource Acquisition Is Initialization,資源獲取即初始化)機制對普通指針進行的一層封裝。這樣使得智能指針的行為動作像一個指針,本質上卻是一個對象,這樣可以方便管理一個對象的生命周期

優(yōu)缺點:

  • 智能指針由原始指針的封裝,優(yōu)點是可以自動分配內存,不用擔心內存泄漏問題。
  • 用于解決獨占/共享所有權指針的釋放,傳輸等問題。
  • 但是沒有原始指針方便。

一. unique_ptr獨占指針

特點

都是圍繞獨占展開

特點一: 如其名,獨占。也就是說同一個內存空間同時只能有一個指針來管理。

int* pi = new int(10); //利用傳統(tǒng)指針在堆區(qū)開辟一個存放整數的區(qū)域
std::unique_ptr<int> u_pi_01{pi};//通過傳統(tǒng)指針創(chuàng)建智能指針
std::unique_ptr<int> u_pi_02{pi};//有意讓兩個獨占指針同時指向同一個內存區(qū)域

這么寫編譯器不會報錯,但運行時會提示 error:double free detected in tcache 2

這也就印證了第一個特點,一個內存區(qū)域只能由一個指針管理。

特點二: 當指針超出作用域時,內存自動釋放

//由于指針的本質也是變量,離開作用范圍就會自動釋放
//因此我們需要通過在外部創(chuàng)建變量來保存指針所保存的地址
int* external_pi_1;//用于存儲傳統(tǒng)指針的地址
int* external_pi_2;//用于存儲智能指針的地址
 {
    int *pi = new int(10);//使用傳統(tǒng)指針在堆區(qū)開辟內存存儲整形
    external_pi_1 = pi;   
    std::unique_ptr<int> u_pi{new int(10)};//使用智能指針在堆區(qū)開辟內存存儲
    external_pi_2 = u_pi.get();
    std::cout << *external_pi_1 << std::endl;//輸出10
    std::cout << *external_pi_2 << std::endl;//輸出10
 }
std::cout << *external_pi_1 << std::endl;//輸出10
std::cout << *external_pi_2 << std::endl;//輸出0

可見傳統(tǒng)指針在局部作用域中開辟的內存在外部同樣可以訪問,也就是說我們使用傳統(tǒng)指針開辟內存之后在離開作用域時需要加上釋放內存的操作,不然會造成內存泄漏。

而智能指針我們不需要手動釋放內存,在離開作用域后會自動釋放。

特點三:由于特點一,修改指針不可以copy ,只能Move(轉移歸屬權)

std::unique_ptr<int> u_pi1 = std::make_unique<int>(10);
//std::unique_ptr<int> u_pi2 = u_pi1;//嘗試用拷貝的方式共享內存,error:可別忘了這是獨占指針
std::unique_ptr<int> u_pi2 = move(u_pi1);使用move方法轉移內存擁有權。

也就是說,通過move函數,把指針u_pi1所指內存中的值掏空,然后安到指針u_pi2所指的內存上。

創(chuàng)建方式

方式一: 通過已有的傳統(tǒng)指針創(chuàng)建

int* pi = new int(10); //使用傳統(tǒng)指針在堆區(qū)開辟一個空間
std::unique_ptr<int> u_pi{pi};//利用創(chuàng)通指針創(chuàng)建智能指針

方式二: 通過new方法創(chuàng)建

std::unique_ptr<int> u_pi{new int(10)};

方式三: 通過std :: make_unique創(chuàng)建

std::unipue_ptr<int> u_pi = std::make_unique<int>(10);

傳遞方式

方式一: 通過move(),轉移擁有權.

void show(std::unique_ptr<int> u_pi)
{
    std::cout<<*u_pi<<std::endl;
}
void test()
{
    std::unique_ptr<int> u_pi{new int(10)};
    show(move(u_pi)); //通過move轉移擁有權
}

注意:將指針的擁有權轉入函數中后,在原作用域指針將被釋放,而該指針將在函數調用結束時釋放。也就是說,將智能指針以move的形式傳入函數后,在原作用域不能再使用該指針。

方式二: 通過引用傳遞

void show(const std::unique_ptr<int> &u_pi)//加cosnt 不是不能改變指向的值,不能改變指針的指向
{
    std::cout << *u_pi << std::endl;
    //u_pi.reset();加了const所以不能清空
}
void test()
{
    std::unique_ptr<int> u_pi{new int(10)};
    show(u_pi);
}

注意: 將指針以引用的方式傳入函數,那么該指針在原作用域依然存活,并可以和所調用函數共同操作該內存空間數據。

方式三: 鏈式傳遞

std::unique_ptr<Person> get_unique(std::string str)
{
    std::unique_ptr<Person> u_pi{new Person(str)};
    return u_pi;
}
void test()
{
    get_unique("hua")->show();//鏈式
}

簡單使用

  • 通過get()獲取地址
  • 可以通過->調用成員函數
  • 可以通過*調用解引用
  • 通過reset()清空指針
class Person
{
public:
    Perosn(std::string name):m_name(name){};
    void show()
    {
        std::cout<<"name is "<<m_name<<std::endl;
    }
private:
    std::string m_name;   
};
int main()
{
std::unique_ptr<Person> u_p{new Person("kimi")}; //用自定義類型創(chuàng)建
u_p->show();//可以通過->調用函數
(*u_p).show();//通過*解引用
std::cout<<u_p.get()<<std::endl;//通過get()獲取地址
u_p.reset();//清空指針
return 0;
}

隱藏危險

用已有指針創(chuàng)建時,沒有及時清空傳統(tǒng)指針,導致同時有兩個指針指向這塊已經被“獨占”的區(qū)域。

int* pi = new int(10);
std::unique_ptr<int> u_pi{pi};//使用傳統(tǒng)指針創(chuàng)建,上式開辟的區(qū)域被獨占
*pi = 20; //沒有及時清空,依然可以通過獨占指針以外的方式修改內存

二. shared_ptr 計數指針

特點

特點一: 可以通過copy共享內存。

std::shared_ptr<int> u_pi_1{new int(10)};
std::shared_ptr<int> u_pi_2 = u_pi_1;//通過復制拷貝

特點二: 通過use_count();來查看計數 ,copy 計數加一,銷毀計數減一。

std::shanred_ptr<int> s_pi{new int(10)}; //s_pi.use_count() == 1
std::shanred_ptr<int> s_pi_copy = s_pi;  //s_pi.use_count() == 2
s_pi = nullptr;//清空指針                 //s_pi_copy.use_count() == 1

特點三: 無論多少指針,都同用一份數據,因而同一份數據的use_count()一致。

std::shared_ptr<int> s_pi{new int(10)}; //s_pi.use_count() == 1
std::shared_ptr<int> s_pi_2 = s_pi;     //s_pi.use_count() == 2
std::shared_ptr<int> s_pi_3 = s_pi_2;   //s_pi.use_count() == 3
s_pi_2 = bullptr; //清空2指針            //s_pi.use_count() == 2

傳遞方式

  • 本質不變,在函數調用中,因為本身支持復制操作,所以不用加move可以直接傳遞。
  • 并且在傳遞到函數中,use_count() 會增加,并在函數銷毀時候還原。
  • 在函數中修改指向的值,在外部的指針指向的值也會改變。
  • 使用引用傳遞,則在傳遞到函數中時,計數不會增加。
void get_use_1(std::shared_ptr<int> s_pi)
{
    std::cout << s_pi.use_count() << std::endl;
}
void get_use_2(std::shared_ptr<int>& s_pi)
{
    std::cout << s_pi.use_count() << std::endl;
}
void test()
{
    std::shared_ptr<int> s_pi{new int(10)};
    std::cout << s_pi.use_count() << std::endl;
    get_use_1(s_pi);//在函數中計數會增加,但隨著函數銷毀,計數復原
    get_use_2(s_pi);//以引用方式傳入,指針還是那個指針,計數不會增加
}

輸出:1 2 1

隱藏危險

share_ptr帶來的循環(huán)依賴問題

class Person
{
public:
    void set_friend(share_ptr<Person> p)
 
    _friend = p;
private:
    share_ptr<Person> _frient;
};
int main()
{
   share_ptr<Person> p1 = make_shared("P1");
   share_ptr<Person> p2 = make_shared("P2");
    p1->set_friend(P2);
    p2->set_friend(P1);//造成循環(huán)依賴,在main中的話,不會執(zhí)行析構
}

解決:將_friend屬性改為weak_ptr 。

三. weak_ptr

weak_ptr 是一個不需要所有權的指針,所以我們可以通過用weak_ptr來聲明屬性,解決循環(huán)依賴

class Person
{
public:
    void set_friend(share_ptr<Person> p)
    _friend = p;
private:
    weak_ptr<Person> _frient;//使用weak_ptr解決循環(huán)依賴
};
int main()
{
    share_ptr<Person> p1 = make_shared("P1");
    share_ptr<Person> p2 = make_shared("P2");
    p1->set_friend(P2);
    p2->set_friend(P1);
}

可以通過lock()來將weak_pte升級為shared_ptr;

std::weak_ptr<Person> w_pi{new Person("hua")};
std::shared_ptr <Person> s_pi2 = w_pi.lock();

到此這篇關于C++智能指針詳解的文章就介紹到這了,更多相關C++智能指針內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • VS2019實現C++的第一個MFC程序

    VS2019實現C++的第一個MFC程序

    本文主要介紹了VS2019實現C++的第一個MFC程序,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-06-06
  • C語言實現簡單的通訊錄

    C語言實現簡單的通訊錄

    這篇文章主要為大家詳細介紹了C語言實現簡單的通訊錄,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • C語言中進行大小寫字母轉化的示例代碼

    C語言中進行大小寫字母轉化的示例代碼

    C語言標準庫中提供了用于大小寫轉換的函數,使得這一操作變得簡單而高效,本文將詳細介紹如何在C語言中進行大小寫字母的轉換,包括相關的函數和示例代碼,需要的朋友可以參考下
    2024-03-03
  • C語言之單鏈表的插入、刪除與查找

    C語言之單鏈表的插入、刪除與查找

    本篇文章主要介紹了從單鏈表的創(chuàng)建、遍歷到節(jié)點的插入、刪除與查找功能的實現,有需要的朋友可以參考下
    2015-07-07
  • C++使用ffmpeg實現rtsp取流的代碼

    C++使用ffmpeg實現rtsp取流的代碼

    這篇文章主要介紹了C++使用ffmpeg實現rtsp取流,文章介紹了ffmepg采用rtsp取流流程圖,CMakeLists.txt編寫方法,通過示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • 使用C# 判斷給定大數是否為質數的詳解

    使用C# 判斷給定大數是否為質數的詳解

    本篇文章是對使用C#判斷給定大數是否為質數的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • 一起來學習C語言的程序環(huán)境與預處理

    一起來學習C語言的程序環(huán)境與預處理

    這篇文章主要為大家詳細介紹了C語言程序環(huán)境與預處理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 詳解C語言如何實現配置文件的讀寫

    詳解C語言如何實現配置文件的讀寫

    這篇文章主要為大家詳細介紹了如何使用C語言實現配置文件的讀寫,包括定義全局宏、公用函數、比較字符串等功能,需要的可以參考一下
    2024-11-11
  • C++回溯算法中組合的相關問題分析

    C++回溯算法中組合的相關問題分析

    回溯算法并不是什么高效的算法,因為本質上時去遍歷所有元素,找出所有可能,然后選出需要的答案。那為什么還要回溯法,簡單來說,不是所有的問題都能用什么巧妙的方法來解決的
    2023-03-03
  • Qt數據庫應用之通用數據庫同步

    Qt數據庫應用之通用數據庫同步

    數據庫同步的主要功能是將本地的數據庫記錄同步到遠程的數據庫。本文將利用Qt實現通用數據庫同步功能,感興趣的小伙伴可以跟隨小編一起學習一下
    2022-03-03

最新評論

肥东县| 武胜县| 泌阳县| 九寨沟县| 永丰县| 鄢陵县| 山阳县| 麻城市| 察哈| 老河口市| 营口市| 阳朔县| 临夏县| 浮山县| 祁东县| 易门县| 休宁县| 湖南省| 镇坪县| 芜湖县| 锡林郭勒盟| 广汉市| 来安县| 定襄县| 竹北市| 玉树县| 永善县| 阳新县| 平山县| 潞西市| 会昌县| 石家庄市| 西宁市| 桂东县| 浮梁县| 务川| 上蔡县| 娄烦县| 广丰县| 芜湖县| 普格县|