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

深入學(xué)習(xí)C++智能指針之shared_ptr與右值引用的方法

 更新時(shí)間:2021年07月13日 08:53:22   作者:進(jìn)擊的汪sir  
智能指針的核心實(shí)現(xiàn)技術(shù)是引用計(jì)數(shù),每使用它一次,內(nèi)部引用計(jì)數(shù)加1,每析構(gòu)一次內(nèi)部的引用計(jì)數(shù)減1,減為0時(shí),刪除所指向的堆內(nèi)存,今天通過(guò)本文給大家分享C++智能指針之shared_ptr與右值引用的方法,需要的朋友跟隨小編一起看看吧

1. 介紹

在 C++ 中沒(méi)有垃圾回收機(jī)制,必須自己釋放分配的內(nèi)存,否則就會(huì)造成內(nèi)存泄露。解決這個(gè)問(wèn)題最有效的方法是使用智能指針(smart pointer)。智能指針是存儲(chǔ)指向動(dòng)態(tài)分配(堆)對(duì)象指針的類(lèi),用于生存期的控制,能夠確保在離開(kāi)指針?biāo)谧饔糜驎r(shí),自動(dòng)地銷(xiāo)毀動(dòng)態(tài)分配的對(duì)象,防止內(nèi)存泄露。智能指針的核心實(shí)現(xiàn)技術(shù)是引用計(jì)數(shù),每使用它一次,內(nèi)部引用計(jì)數(shù)加1,每析構(gòu)一次內(nèi)部的引用計(jì)數(shù)減1,減為0時(shí),刪除所指向的堆內(nèi)存。

C++11 中提供了三種智能指針,使用這些智能指針時(shí)需要引用頭文件

  • std::shared_ptr:共享的智能指針
  • std::unique_ptr:獨(dú)占的智能指針
  • std::weak_ptr:弱引用的智能指針,它不共享指針,不能操作資源,是用來(lái)監(jiān)視 shared_ptr 的。

共享智能指針(shared_ptr)是指多個(gè)智能指針可以同時(shí)管理同一塊有效的內(nèi)存,共享智能指針 shared_ptr 是一個(gè)模板類(lèi),如果要進(jìn)行初始化有三種方式:通過(guò)構(gòu)造函數(shù)、std::make_shared 輔助函數(shù)以及 reset 方法。共享智能指針對(duì)象初始化完畢之后就指向了要管理的那塊堆內(nèi)存,如果想要查看當(dāng)前有多少個(gè)智能指針同時(shí)管理著這塊內(nèi)存可以使用共享智能指針提供的一個(gè)成員函數(shù) use_count

2. 初始化方法

2.1 通過(guò)構(gòu)造函數(shù)初始化

實(shí)例

// 使用智能指針管理一塊 int 型的堆內(nèi)存
shared_ptr<int> ptr1(new int(520));

2.2 通過(guò)拷貝和移動(dòng)構(gòu)造函數(shù)初始化

調(diào)用拷貝構(gòu)造函數(shù)

shared_ptr<int> ptr2(ptr1);

調(diào)用移動(dòng)構(gòu)造函數(shù)

std::shared_ptr<int> ptr5 = std::move(ptr2);

如果使用拷貝的方式初始化共享智能指針對(duì)象,這兩個(gè)對(duì)象會(huì)同時(shí)管理同一塊堆內(nèi)存,堆內(nèi)存對(duì)應(yīng)的引用計(jì)數(shù)也會(huì)增加;
如果使用移動(dòng)的方式初始智能指針對(duì)象,只是轉(zhuǎn)讓了內(nèi)存的所有權(quán),管理內(nèi)存的對(duì)象并不會(huì)增加,因此內(nèi)存的引用計(jì)數(shù)不會(huì)變化。

2.2.1 移動(dòng)構(gòu)造

關(guān)于移動(dòng)構(gòu)造,可能有些讀者不太明白

移動(dòng)構(gòu)造是C++11標(biāo)準(zhǔn)中提供的一種新的構(gòu)造方法。

在現(xiàn)實(shí)中有很多這樣的例子,我們將錢(qián)從一個(gè)賬號(hào)轉(zhuǎn)移到另一個(gè)賬號(hào),將手機(jī)SIM卡轉(zhuǎn)移到另一臺(tái)手機(jī),將文件從一個(gè)位置剪切到另一個(gè)位置……移動(dòng)構(gòu)造可以減少不必要的復(fù)制,帶來(lái)性能上的提升。

我們首先來(lái)看看move函數(shù)
首先看這樣一段代碼

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

int main()
{
	string st = "I love 進(jìn)擊的汪sir";
	vector<string> vc;
	vc.push_back(move(st));
	cout << vc[0] << endl;
	if (!st.empty())
		cout << st << endl;

	return 0;
}

輸出的結(jié)果為

再看這樣一段代碼

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

int main()
{
	string st = "I love xing";
	vector<string> vc;
	vc.push_back(st);
	cout << vc[0] << endl;
	if (!st.empty())
		cout << st << endl;

	return 0;
}

其結(jié)果為

這兩段代碼唯一的不同是調(diào)用vc.push_back()將字符串插入到容器中去時(shí),第一段代碼使用了move語(yǔ)句,而第二段代碼沒(méi)有使用move語(yǔ)句。輸出的結(jié)果差異也很明顯,第一段代碼中,原來(lái)的字符串st已經(jīng)為空,而第二段代碼中,原來(lái)的字符串st的內(nèi)容沒(méi)有變化。

先暫時(shí)記住這兩端代碼的輸出結(jié)果之間的差異。
我們回到移動(dòng)構(gòu)造函數(shù)上

有時(shí)候我們會(huì)遇到這樣一種情況,我們用對(duì)象a初始化對(duì)象b,后對(duì)象a我們就不在使用了,但是對(duì)象a的空間還在呀(在析構(gòu)之前),既然拷貝構(gòu)造函數(shù),實(shí)際上就是把a(bǔ)對(duì)象的內(nèi)容復(fù)制一份到b中,那么為什么我們不能直接使用a的空間呢?這樣就避免了新的空間的分配,大大降低了構(gòu)造的成本。這就是移動(dòng)構(gòu)造函數(shù)設(shè)計(jì)的初衷。

通俗一點(diǎn)的解釋就是,拷貝構(gòu)造函數(shù)中,對(duì)于指針,我們一定要采用深層復(fù)制,而移動(dòng)構(gòu)造函數(shù)中,對(duì)于指針,我們采用淺層復(fù)制。

所以在上面的例子中,如果調(diào)用移動(dòng)構(gòu)造函數(shù)來(lái)初始化智能指針,引用計(jì)數(shù)是不會(huì)增加的,而move函數(shù)實(shí)際上是返回的右值引用

2.2.2 右值引用

上面我們講到了右值引用,這里就來(lái)擴(kuò)展一下右值引用是啥
首先得分清楚,什么是右值,什么是左值

  • lvalue 是 loactor value 的縮寫(xiě),rvalue 是 read value 的縮寫(xiě)
  • 左值是指存儲(chǔ)在內(nèi)存中、有明確存儲(chǔ)地址(可取地址)的數(shù)據(jù);
  • 右值是指可以提供數(shù)據(jù)值的數(shù)據(jù)(不可取地址);

通過(guò)描述可以看出,區(qū)分左值與右值的便捷方法是:可以對(duì)表達(dá)式取地址(&)就是左值,否則為右值 。所有有名字的變量或?qū)ο蠖际亲笾?,而右值是匿名的?/p>

C++11 中右值可以分為兩種:一個(gè)是將亡值( xvalue, expiring value),另一個(gè)則是純右值( prvalue, PureRvalue):

  • 純右值:非引用返回的臨時(shí)變量、運(yùn)算表達(dá)式產(chǎn)生的臨時(shí)變量、原始字面量和 lambda 表達(dá)式等
  • 將亡值:與右值引用相關(guān)的表達(dá)式,比如,T&& 類(lèi)型函數(shù)的返回值、 std::move 的返回值等。

右值引用就是對(duì)一個(gè)右值進(jìn)行引用的類(lèi)型。因?yàn)橛抑凳悄涿模晕覀冎荒芡ㄟ^(guò)引用的方式找到它。無(wú)論聲明左值引用還是右值引用都必須立即進(jìn)行初始化,因?yàn)橐妙?lèi)型本身并不擁有所綁定對(duì)象的內(nèi)存,只是該對(duì)象的一個(gè)別名。通過(guò)右值引用的聲明,該右值又“重獲新生”,其生命周期與右值引用類(lèi)型變量的生命周期一樣,只要該變量還活著,該右值臨時(shí)量將會(huì)一直存活下去。

右值通過(guò)&&來(lái)引用

例如:

  • int&& value = 520; 里面 520 是純右值,value 是對(duì)字面量 520 這個(gè)右值的引用。
  • int &&a2 = a1; 中 a1 雖然寫(xiě)在了 = 右邊,但是它仍然是一個(gè)左值,使用左值初始化一個(gè)右值引用類(lèi)型是不合法的。
  • const Test& t = getObj() 這句代碼的語(yǔ)法是正確的,常量左值引用是一個(gè)萬(wàn)能引用類(lèi)型,它可以接受左值、右值、常量左值和常量右值。

2.3 通過(guò) std::make_shared 初始化

通過(guò) C++ 提供的 std::make_shared() 就可以完成內(nèi)存對(duì)象的創(chuàng)建并將其初始化給智能指針,函數(shù)原型如下:

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );

實(shí)例
使用智能指針管理一塊 int 型的堆內(nèi)存, 內(nèi)部引用計(jì)數(shù)為 1

shared_ptr<int> ptr1 = make_shared<int>(520);

注意
使用 std::make_shared() 模板函數(shù)可以完成內(nèi)存地址的創(chuàng)建,并將最終得到的內(nèi)存地址傳遞給共享智能指針對(duì)象管理。如果申請(qǐng)的內(nèi)存是普通類(lèi)型,通過(guò)函數(shù)的()可完成地址的初始化,如果要?jiǎng)?chuàng)建一個(gè)類(lèi)對(duì)象,函數(shù)的()內(nèi)部需要指定構(gòu)造對(duì)象需要的參數(shù),也就是類(lèi)構(gòu)造函數(shù)的參數(shù)。

2.4 通過(guò) reset 方法初始化

共享智能指針類(lèi)提供的 std::shared_ptr::reset 方法函數(shù)原型如下:

void reset() noexcept;

template< class Y >
void reset( Y* ptr );

template< class Y, class Deleter >
void reset( Y* ptr, Deleter d );

template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc );
  • ptr:指向要取得所有權(quán)的對(duì)象的指針
  • d:指向要取得所有權(quán)的對(duì)象的指針
  • aloc:內(nèi)部存儲(chǔ)所用的分配器

實(shí)例

shared_ptr<int> ptr5;
ptr5.reset(new int(250));

3. 獲取原始指針

對(duì)應(yīng)基礎(chǔ)數(shù)據(jù)類(lèi)型來(lái)說(shuō),通過(guò)操作智能指針和操作智能指針管理的內(nèi)存效果是一樣的,可以直接完成數(shù)據(jù)的讀寫(xiě)。但是如果共享智能指針管理的是一個(gè)對(duì)象,那么就需要取出原始內(nèi)存的地址再操作,可以調(diào)用共享智能指針類(lèi)提供的 get () 方法得到原始地址,其函數(shù)原型如下:

T* get() const noexcept;

實(shí)例

#include <iostream>
#include <string>
#include <memory>
using namespace std;

int main()
{
    int len = 128;
    shared_ptr<char> ptr(new char[len]);
    // 得到指針的原始地址
    char* add = ptr.get();
    memset(add, 0, len);
    strcpy(add, "博客:進(jìn)擊的汪sir");
    cout << "string: " << add << endl;
    
    shared_ptr<int> p(new int);
    *p = 100;
    cout << *p.get() << "  " << *p << endl;
    
    return 0;
}

4. 指定刪除器

當(dāng)智能指針管理的內(nèi)存對(duì)應(yīng)的引用計(jì)數(shù)變?yōu)?0 的時(shí)候,這塊內(nèi)存就會(huì)被智能指針析構(gòu)掉了。另外,我們?cè)诔跏蓟悄苤羔樀臅r(shí)候也可以自己指定刪除動(dòng)作,這個(gè)刪除操作對(duì)應(yīng)的函數(shù)被稱(chēng)之為刪除器,這個(gè)刪除器函數(shù)本質(zhì)是一個(gè)回調(diào)函數(shù),我們只需要進(jìn)行實(shí)現(xiàn),其調(diào)用是由智能指針完成的。

實(shí)例

#include <iostream>
#include <memory>
using namespace std;

// 自定義刪除器函數(shù),釋放int型內(nèi)存
void deleteIntPtr(int* p)
{
    delete p;
    cout << "int 型內(nèi)存被釋放了...";
}

int main()
{
    shared_ptr<int> ptr(new int(250), deleteIntPtr);
    return 0;
}

刪除器函數(shù)也可以是 lambda 表達(dá)式!

5. 參考鏈接

https://subingwen.cn/cpp/shared_ptr/
https://www.cnblogs.com/qingergege/p/7607089.html

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

相關(guān)文章

  • C++?超詳細(xì)示例講解list的使用

    C++?超詳細(xì)示例講解list的使用

    list是一種序列式容器。list容器完成的功能實(shí)際上和數(shù)據(jù)結(jié)構(gòu)中的雙向鏈表是極其相似的,list中的數(shù)據(jù)元素是通過(guò)鏈表指針串連成邏輯意義上的線性表,也就是list也具有鏈表的主要優(yōu)點(diǎn),即:在鏈表的任一位置進(jìn)行元素的插入、刪除操作都是快速的
    2022-07-07
  • C++實(shí)現(xiàn)線性表順序存儲(chǔ)的示例代碼

    C++實(shí)現(xiàn)線性表順序存儲(chǔ)的示例代碼

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)線性表順序存儲(chǔ)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下
    2023-03-03
  • C語(yǔ)言詳解無(wú)頭單向非循環(huán)鏈表各種操作方法

    C語(yǔ)言詳解無(wú)頭單向非循環(huán)鏈表各種操作方法

    無(wú)頭單向非循環(huán)鏈表:結(jié)構(gòu)簡(jiǎn)單,一般不會(huì)單獨(dú)用來(lái)存數(shù)據(jù)。實(shí)際中更多是作為其他數(shù)據(jù)結(jié)構(gòu)的子結(jié)構(gòu),如哈希桶、圖的鄰接表等等。另外這種結(jié)構(gòu)在筆試面試中出現(xiàn)很多
    2022-04-04
  • C語(yǔ)言編程中實(shí)現(xiàn)二分查找的簡(jiǎn)單入門(mén)實(shí)例

    C語(yǔ)言編程中實(shí)現(xiàn)二分查找的簡(jiǎn)單入門(mén)實(shí)例

    這篇文章主要介紹了C語(yǔ)言編程中實(shí)現(xiàn)二分查找的簡(jiǎn)單入門(mén)實(shí)例,需要的朋友可以參考下
    2015-12-12
  • Windows上CLion的配置步驟詳解

    Windows上CLion的配置步驟詳解

    這篇文章主要介紹了Windows上CLion的配置,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 十分鐘學(xué)會(huì)C++?Traits

    十分鐘學(xué)會(huì)C++?Traits

    本文試圖以最簡(jiǎn)潔的方式闡述對(duì)C++?traits?的理解,當(dāng)你理解了第二個(gè)例子的時(shí)候,相信你已經(jīng)理解了C++?traits,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-02-02
  • C語(yǔ)言如何求整數(shù)的位數(shù)及各位數(shù)字之和

    C語(yǔ)言如何求整數(shù)的位數(shù)及各位數(shù)字之和

    這篇文章主要介紹了C語(yǔ)言如何求整數(shù)的位數(shù)及各位數(shù)字之和,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語(yǔ)言實(shí)現(xiàn)打飛機(jī)小游戲

    C語(yǔ)言實(shí)現(xiàn)打飛機(jī)小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的打飛機(jī)小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C++20中的結(jié)構(gòu)化綁定類(lèi)型示例詳解

    C++20中的結(jié)構(gòu)化綁定類(lèi)型示例詳解

    這篇文章主要為大家介紹了C++20中的結(jié)構(gòu)化綁定類(lèi)型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • C語(yǔ)言實(shí)現(xiàn)魔方陣算法(幻方陣 奇魔方 單偶魔方實(shí)現(xiàn))

    C語(yǔ)言實(shí)現(xiàn)魔方陣算法(幻方陣 奇魔方 單偶魔方實(shí)現(xiàn))

    魔方陣是指由1,2,3……n2填充的,每一行、每一列、對(duì)角線之和均相等的方陣,階數(shù)n = 3,4,5…。魔方陣也稱(chēng)為幻方陣,看下面的實(shí)現(xiàn)方法吧
    2013-11-11

最新評(píng)論

台山市| 安阳县| 青浦区| 孙吴县| 余江县| 特克斯县| 河北区| 康平县| 呈贡县| 马龙县| 弥勒县| 虞城县| 安顺市| 乐都县| 黄平县| 博乐市| 峨边| 新晃| 佳木斯市| 民权县| 沙洋县| 黄山市| 汝阳县| 石阡县| 雅江县| 通化县| 任丘市| 济南市| 枞阳县| 修武县| 丹巴县| 崇明县| 南涧| 利津县| 开封县| 乐清市| 宁晋县| 兴安县| 新邵县| 漳浦县| 彩票|