亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

在 C++ 98/03 標(biāo)準(zhǔn)中,如果想用其它對象初始化一個(gè)同類的新對象,只能借助類中的拷貝構(gòu)造函數(shù)。拷貝構(gòu)造函數(shù)的實(shí)現(xiàn)原理很簡單,就是為新對象復(fù)制一份和其它對象一模一樣的數(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è)對象中的指針成員指向同一塊堆空間,這些對象析構(gòu)時(shí)就會(huì)對該空間釋放多次,這是不允許的。

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

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

注意,目前多數(shù)編譯器都會(huì)對程序中發(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)生的匿名對象
copy construct!    <-- 執(zhí)行 a = get_demo()
class destruct!     <-- 銷毀 get_demo() 返回的臨時(shí)對象
class destruct!     <-- 銷毀 a

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

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

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

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

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

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

事實(shí)上,對于程序執(zhí)行過程中產(chǎn)生的臨時(shí)對象,往往只用于傳遞數(shù)據(jù)(沒有其它的用處),并且會(huì)很快會(huì)被銷毀。因此在使用臨時(shí)對象初始化新對象時(shí),我們可以將其包含的指針成員指向的內(nèi)存資源直接移給新對象所有,無需再新拷貝一份,這大大提高了初始化的執(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,有效避免了“同一塊對空間被釋放多次”情況的發(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!

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

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

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

默認(rèn)情況下,左值初始化同類對象只能通過拷貝構(gòu)造函數(shù)完成,如果想調(diào)用移動(dòng)構(gòu)造函數(shù),則必須使用右值進(jìn)行初始化。C++11 標(biāo)準(zhǔn)中為了滿足用戶使用左值初始化同類對象時(shí)也通過移動(dòng)構(gòu)造函數(shù)完成的需求,新引入了 std::move() 函數(shù),它可以將左值強(qiáng)制轉(zhuǎn)換成對應(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Qt界面美化之自定義qss樣式表的詳細(xì)步驟

    Qt界面美化之自定義qss樣式表的詳細(xì)步驟

    很多人應(yīng)該和我一樣,想做界面才接觸的Qt,結(jié)果就是做不出來華麗的界面,下面這篇文章主要給大家介紹了關(guān)于Qt界面美化之自定義qss樣式表的詳細(xì)步驟,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • C語言中extern詳細(xì)用法解析

    C語言中extern詳細(xì)用法解析

    這篇文章主要介紹了C語言中extern詳細(xì)用法解析,本文講解的extern也是C語言中的關(guān)鍵詞,用來修飾函數(shù)聲明或變量等,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++編程中break語句和continue語句的學(xué)習(xí)教程

    C++編程中break語句和continue語句的學(xué)習(xí)教程

    這篇文章主要介紹了C++編程中break語句和continue語句的學(xué)習(xí)教程,break和continue是C++循環(huán)控制中的基礎(chǔ)語句,需要的朋友可以參考下
    2016-01-01
  • C語言算術(shù)運(yùn)算符整理

    C語言算術(shù)運(yùn)算符整理

    算術(shù)運(yùn)算符用于各類數(shù)值運(yùn)算,包括加(+)、減(-)、乘(*)、除(/)、求余(或稱模運(yùn)算,%)、自增(++)、自減(--)共七種
    2023-03-03
  • visual studio code 配置C++開發(fā)環(huán)境的教程詳解 (windows 開發(fā)環(huán)境)

    visual studio code 配置C++開發(fā)環(huán)境的教程詳解 (windows 開發(fā)環(huán)境)

    這篇文章主要介紹了 windows 開發(fā)環(huán)境下visual studio code 配置C++開發(fā)環(huán)境的圖文教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • C++ assert()函數(shù)用法案例詳解

    C++ assert()函數(shù)用法案例詳解

    這篇文章主要介紹了C++ assert()函數(shù)用法案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • C語言結(jié)構(gòu)體(struct)的詳細(xì)講解

    C語言結(jié)構(gòu)體(struct)的詳細(xì)講解

    C語言中,結(jié)構(gòu)體類型屬于一種構(gòu)造類型(其他的構(gòu)造類型還有:數(shù)組類型,聯(lián)合類型),下面這篇文章主要給大家介紹了關(guān)于C語言結(jié)構(gòu)體(struct)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03
  • C++?LeetCode0547題解省份數(shù)量圖的連通分量

    C++?LeetCode0547題解省份數(shù)量圖的連通分量

    這篇文章主要為大家介紹了C++?LeetCode0547題解省份數(shù)量圖的連通分量示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • C++實(shí)現(xiàn)猴子吃桃的示例代碼

    C++實(shí)現(xiàn)猴子吃桃的示例代碼

    這篇文章主要介紹了C++實(shí)現(xiàn)猴子吃桃的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法

    C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法

    這篇文章主要介紹了C++歸并法+快速排序?qū)崿F(xiàn)鏈表排序的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04

最新評論