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

C++11中移動(dòng)構(gòu)造函數(shù)案例代碼

 更新時(shí)間:2023年01月04日 09:27:03   作者:crossoverpptx  
C++11 標(biāo)準(zhǔn)中為了滿足用戶使用左值初始化同類對(duì)象時(shí)也通過(guò)移動(dòng)構(gòu)造函數(shù)完成的需求,新引入了 std::move() 函數(shù),它可以將左值強(qiáng)制轉(zhuǎn)換成對(duì)應(yīng)的右值,由此便可以使用移動(dòng)構(gòu)造函數(shù),對(duì)C++11移動(dòng)構(gòu)造函數(shù)相關(guān)知識(shí)感興趣的朋友一起看看吧

1. 拷貝構(gòu)造函數(shù)中的深拷貝問(wèn)題

在 C++ 98/03 標(biāo)準(zhǔn)中,如果想用其它對(duì)象初始化一個(gè)同類的新對(duì)象,只能借助類中的拷貝構(gòu)造函數(shù)。拷貝構(gòu)造函數(shù)的實(shí)現(xiàn)原理很簡(jiǎn)單,就是為新對(duì)象復(fù)制一份和其它對(duì)象一模一樣的數(shù)據(jù)。需要注意的是,當(dāng)類中擁有指針類型的成員變量時(shí),拷貝構(gòu)造函數(shù)中需要以深拷貝(而非淺拷貝)的方式復(fù)制該指針成員。

舉個(gè)例子:

#include <iostream>
using namespace std;

class demo{
public:
   demo():num(new int(0)){
      cout<<"construct!"<<endl;
   }
   //拷貝構(gòu)造函數(shù)
   demo(const demo &d):num(new int(*d.num)){
      cout<<"copy construct!"<<endl;
   }
   ~demo(){
      cout<<"class destruct!"<<endl;
   }
private:
   int *num;
};

demo get_demo(){
    return demo();
}

int main(){
    demo a = get_demo();
    return 0;
}

如上所示,我們?yōu)?demo 類自定義了一個(gè)拷貝構(gòu)造函數(shù)。該函數(shù)在拷貝 d.num 指針成員時(shí),必須采用深拷貝的方式,即拷貝該指針成員本身的同時(shí),還要拷貝指針指向的內(nèi)存資源。否則一旦多個(gè)對(duì)象中的指針成員指向同一塊堆空間,這些對(duì)象析構(gòu)時(shí)就會(huì)對(duì)該空間釋放多次,這是不允許的。

可以看到,程序中定義了一個(gè)可返回 demo 對(duì)象的 get_demo() 函數(shù),用于在 main() 主函數(shù)中初始化 a 對(duì)象,其整個(gè)初始化的流程包含以下幾個(gè)階段:

  • 執(zhí)行 get_demo() 函數(shù)內(nèi)部的 demo() 語(yǔ)句,即調(diào)用 demo 類的默認(rèn)構(gòu)造函數(shù)生成一個(gè)匿名對(duì)象;
  • 執(zhí)行 return demo() 語(yǔ)句,會(huì)調(diào)用拷貝構(gòu)造函數(shù)復(fù)制一份之前生成的匿名對(duì)象,并將其作為 get_demo() 函數(shù)的返回值(函數(shù)體執(zhí)行完畢之前,匿名對(duì)象會(huì)被析構(gòu)銷毀);
  • 執(zhí)行 a = get_demo() 語(yǔ)句,再調(diào)用一次拷貝構(gòu)造函數(shù),將之前拷貝得到的臨時(shí)對(duì)象復(fù)制給 a(此行代碼執(zhí)行完畢,get_demo() 函數(shù)返回的對(duì)象會(huì)被析構(gòu));
  • 程序執(zhí)行結(jié)束前,會(huì)自行調(diào)用 demo 類的析構(gòu)函數(shù)銷毀 a。

注意,目前多數(shù)編譯器都會(huì)對(duì)程序中發(fā)生的拷貝操作進(jìn)行優(yōu)化,因此如果我們使用 VS 2017、codeblocks 等這些編譯器運(yùn)行此程序時(shí),看到的往往是優(yōu)化后的輸出結(jié)果:

construct!
class destruct!

而同樣的程序,如果在 Linux 上使用g++ demo.cpp -fno-elide-constructors命令運(yùn)行(其中 demo.cpp 是程序文件的名稱),就可以看到完整的輸出結(jié)果:

construct!        <-- 執(zhí)行 demo()
copy construct!    <-- 執(zhí)行 return demo()
class destruct!     <-- 銷毀 demo() 產(chǎn)生的匿名對(duì)象
copy construct!    <-- 執(zhí)行 a = get_demo()
class destruct!     <-- 銷毀 get_demo() 返回的臨時(shí)對(duì)象
class destruct!     <-- 銷毀 a

如上所示,利用拷貝構(gòu)造函數(shù)實(shí)現(xiàn)對(duì) a 對(duì)象的初始化,底層實(shí)際上進(jìn)行了 2 次拷貝(而且是深拷貝)操作。當(dāng)然,對(duì)于僅申請(qǐng)少量堆空間的臨時(shí)對(duì)象來(lái)說(shuō),深拷貝的執(zhí)行效率依舊可以接受,但如果臨時(shí)對(duì)象中的指針成員申請(qǐng)了大量的堆空間,那么 2 次深拷貝操作勢(shì)必會(huì)影響 a 對(duì)象初始化的執(zhí)行效率。

事實(shí)上,此問(wèn)題一直存留在以 C++ 98/03 標(biāo)準(zhǔn)編寫的 C++ 程序中。由于臨時(shí)變量的產(chǎn)生、銷毀以及發(fā)生的拷貝操作本身就是很隱晦的(編譯器對(duì)這些過(guò)程做了專門的優(yōu)化),且并不會(huì)影響程序的正確性,因此很少進(jìn)入程序員的視野。

那么當(dāng)類中包含指針類型的成員變量,使用其它對(duì)象來(lái)初始化同類對(duì)象時(shí),怎樣才能避免深拷貝導(dǎo)致的效率問(wèn)題呢?C++11 標(biāo)準(zhǔn)引入了解決方案,該標(biāo)準(zhǔn)中引入了右值引用的語(yǔ)法,借助它可以實(shí)現(xiàn)移動(dòng)語(yǔ)義。

2. C++移動(dòng)構(gòu)造函數(shù)(移動(dòng)語(yǔ)義的具體實(shí)現(xiàn))

所謂移動(dòng)語(yǔ)義,指的就是以移動(dòng)而非深拷貝的方式初始化含有指針成員的類對(duì)象。簡(jiǎn)單的理解,移動(dòng)語(yǔ)義指的就是將其他對(duì)象(通常是臨時(shí)對(duì)象)擁有的內(nèi)存資源“移為已用”。

以前面程序中的 demo 類為例,該類的成員都包含一個(gè)整形的指針成員,其默認(rèn)指向的是容納一個(gè)整形變量的堆空間。當(dāng)使用 get_demo() 函數(shù)返回的臨時(shí)對(duì)象初始化 a 時(shí),我們只需要將臨時(shí)對(duì)象的 num 指針直接淺拷貝給 a.num,然后修改該臨時(shí)對(duì)象中 num 指針的指向(通常另其指向 NULL),這樣就完成了 a.num 的初始化。

事實(shí)上,對(duì)于程序執(zhí)行過(guò)程中產(chǎn)生的臨時(shí)對(duì)象,往往只用于傳遞數(shù)據(jù)(沒(méi)有其它的用處),并且會(huì)很快會(huì)被銷毀。因此在使用臨時(shí)對(duì)象初始化新對(duì)象時(shí),我們可以將其包含的指針成員指向的內(nèi)存資源直接移給新對(duì)象所有,無(wú)需再新拷貝一份,這大大提高了初始化的執(zhí)行效率。

例如,下面程序?qū)?demo 類進(jìn)行了修改:

#include <iostream>
using namespace std;

class demo{
public:
    demo():num(new int(0)){
        cout<<"construct!"<<endl;
    }
    demo(const demo &d):num(new int(*d.num)){
        cout<<"copy construct!"<<endl;
    }
    //添加移動(dòng)構(gòu)造函數(shù)
    demo(demo &&d):num(d.num){
        d.num = NULL;
        cout<<"move construct!"<<endl;
    }
    ~demo(){
        cout<<"class destruct!"<<endl;
    }
private:
    int *num;
};

demo get_demo(){
    return demo();
}

int main(){
    demo a = get_demo();
    return 0;
}

可以看到,在之前 demo 類的基礎(chǔ)上,我們又手動(dòng)為其添加了一個(gè)構(gòu)造函數(shù)。和其它構(gòu)造函數(shù)不同,此構(gòu)造函數(shù)使用右值引用形式的參數(shù),又稱為移動(dòng)構(gòu)造函數(shù)。并且在此構(gòu)造函數(shù)中,num 指針變量采用的是淺拷貝的復(fù)制方式,同時(shí)在函數(shù)內(nèi)部重置了 d.num,有效避免了“同一塊對(duì)空間被釋放多次”情況的發(fā)生。

在 Linux 系統(tǒng)中使用g++ demo.cpp -o demo.exe -std=c++0x -fno-elide-constructors命令執(zhí)行此程序,輸出結(jié)果為:

construct!
move construct!
class destruct!
move construct!
class destruct!
class destruct!

通過(guò)執(zhí)行結(jié)果我們不難得知,當(dāng)為 demo 類添加移動(dòng)構(gòu)造函數(shù)之后,使用臨時(shí)對(duì)象初始化 a 對(duì)象過(guò)程中產(chǎn)生的 2 次拷貝操作,都轉(zhuǎn)由移動(dòng)構(gòu)造函數(shù)完成。

我們知道,非 const 右值引用只能操作右值,程序執(zhí)行結(jié)果中產(chǎn)生的臨時(shí)對(duì)象(例如函數(shù)返回值、lambda 表達(dá)式等)既無(wú)名稱也無(wú)法獲取其存儲(chǔ)地址,所以屬于右值。當(dāng)類中同時(shí)包含拷貝構(gòu)造函數(shù)和移動(dòng)構(gòu)造函數(shù)時(shí),如果使用臨時(shí)對(duì)象初始化當(dāng)前類的對(duì)象,編譯器會(huì)優(yōu)先調(diào)用移動(dòng)構(gòu)造函數(shù)來(lái)完成此操作。只有當(dāng)類中沒(méi)有合適的移動(dòng)構(gòu)造函數(shù)時(shí),編譯器才會(huì)退而求其次,調(diào)用拷貝構(gòu)造函數(shù)。

在實(shí)際開發(fā)中,通常在類中自定義移動(dòng)構(gòu)造函數(shù)的同時(shí),會(huì)再為其自定義一個(gè)適當(dāng)?shù)目截悩?gòu)造函數(shù),由此當(dāng)用戶利用右值初始化類對(duì)象時(shí),會(huì)調(diào)用移動(dòng)構(gòu)造函數(shù);使用左值(非右值)初始化類對(duì)象時(shí),會(huì)調(diào)用拷貝構(gòu)造函數(shù)。

那么,如果使用左值初始化同類對(duì)象,但也想調(diào)用移動(dòng)構(gòu)造函數(shù)完成,有沒(méi)有辦法可以實(shí)現(xiàn)呢?

默認(rèn)情況下,左值初始化同類對(duì)象只能通過(guò)拷貝構(gòu)造函數(shù)完成,如果想調(diào)用移動(dòng)構(gòu)造函數(shù),則必須使用右值進(jìn)行初始化。C++11 標(biāo)準(zhǔn)中為了滿足用戶使用左值初始化同類對(duì)象時(shí)也通過(guò)移動(dòng)構(gòu)造函數(shù)完成的需求,新引入了 std::move() 函數(shù),它可以將左值強(qiáng)制轉(zhuǎn)換成對(duì)應(yīng)的右值,由此便可以使用移動(dòng)構(gòu)造函數(shù)。

到此這篇關(guān)于C++11中移動(dòng)構(gòu)造函數(shù)的文章就介紹到這了,更多相關(guān)C++11移動(dòng)構(gòu)造函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++?using?編譯指令與名稱沖突問(wèn)題

    C++?using?編譯指令與名稱沖突問(wèn)題

    using?編譯指令由名稱空間名和它前面的關(guān)鍵字?using?namespace?組成,它使名稱空間中的所有名稱都可用,而不需要使用作用域解析運(yùn)算符,這篇文章主要介紹了C++?using?編譯指令與名稱沖突,需要的朋友可以參考下
    2022-11-11
  • C/C++獲取Windows平臺(tái)CPU占用率的方法

    C/C++獲取Windows平臺(tái)CPU占用率的方法

    最近在做系統(tǒng)信息相關(guān)的接口,為了實(shí)現(xiàn)跨平臺(tái),故在linux和Windows平臺(tái)獲取占用率信息,文章主要介紹Windows下的方法,文中給出了參考代碼,需要的朋友可以參考下
    2023-12-12
  • c語(yǔ)言經(jīng)典習(xí)題之逆序字符串詳解

    c語(yǔ)言經(jīng)典習(xí)題之逆序字符串詳解

    這篇文章主要為大家介紹了c語(yǔ)言習(xí)題之逆序字符串,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • C++迭代器失效問(wèn)題及解決

    C++迭代器失效問(wèn)題及解決

    這篇文章主要介紹了C++迭代器失效問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 利用C++開發(fā)一個(gè)protobuf動(dòng)態(tài)解析工具

    利用C++開發(fā)一個(gè)protobuf動(dòng)態(tài)解析工具

    數(shù)據(jù)庫(kù)中存儲(chǔ)的protobuf序列化的內(nèi)容,有時(shí)候查問(wèn)題想直接解析查看內(nèi)容。很多編碼在網(wǎng)上很容易找到編解碼工具,但protobuf沒(méi)有找到編解碼工具,可能這樣的需求比較少吧,那就自己用C++實(shí)現(xiàn)一個(gè),感興趣的可以了解一下
    2023-01-01
  • C語(yǔ)言實(shí)現(xiàn)基于控制臺(tái)的電子時(shí)鐘

    C語(yǔ)言實(shí)現(xiàn)基于控制臺(tái)的電子時(shí)鐘

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)基于控制臺(tái)的電子時(shí)鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C++關(guān)于/2和>>1的區(qū)別說(shuō)明

    C++關(guān)于/2和>>1的區(qū)別說(shuō)明

    這篇文章主要介紹了C++關(guān)于/2和>>1的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++ Boost實(shí)現(xiàn)數(shù)字與字符串轉(zhuǎn)化詳解

    C++ Boost實(shí)現(xiàn)數(shù)字與字符串轉(zhuǎn)化詳解

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱
    2022-11-11
  • C語(yǔ)言中正切的相關(guān)函數(shù)總結(jié)

    C語(yǔ)言中正切的相關(guān)函數(shù)總結(jié)

    這篇文章主要介紹了C語(yǔ)言中正切的相關(guān)函數(shù)總結(jié),包括正切和反正切以及雙曲線正切等的函數(shù),需要的朋友可以參考下
    2015-08-08
  • C語(yǔ)言實(shí)現(xiàn)三子棋實(shí)例代碼

    C語(yǔ)言實(shí)現(xiàn)三子棋實(shí)例代碼

    大家好,本篇文章主要講的是C語(yǔ)言實(shí)現(xiàn)三子棋實(shí)例代碼,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01

最新評(píng)論

石嘴山市| 丰城市| 彰化市| 饶平县| 水城县| 蒙自县| 上思县| 信丰县| 左权县| 泾源县| 灵寿县| 申扎县| 五常市| 达孜县| 屏南县| 黔东| 安塞县| 滨海县| 九龙城区| 德令哈市| 绥棱县| 柘荣县| 汕尾市| 桦川县| 区。| 太保市| 五寨县| 望都县| 凤城市| 常熟市| 二手房| 岳普湖县| 新巴尔虎左旗| 广德县| 卓资县| 湟源县| 营口市| 小金县| 海城市| 武宣县| 阿拉善右旗|