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

C++11中移動構造函數案例代碼

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

1. 拷貝構造函數中的深拷貝問題

在 C++ 98/03 標準中,如果想用其它對象初始化一個同類的新對象,只能借助類中的拷貝構造函數??截悩嬙旌瘮档膶崿F原理很簡單,就是為新對象復制一份和其它對象一模一樣的數據。需要注意的是,當類中擁有指針類型的成員變量時,拷貝構造函數中需要以深拷貝(而非淺拷貝)的方式復制該指針成員。

舉個例子:

#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;
   }
   ~demo(){
      cout<<"class destruct!"<<endl;
   }
private:
   int *num;
};

demo get_demo(){
    return demo();
}

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

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

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

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

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

construct!
class destruct!

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

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

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

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

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

2. C++移動構造函數(移動語義的具體實現)

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

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

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

例如,下面程序對 demo 類進行了修改:

#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;
    }
    //添加移動構造函數
    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 類的基礎上,我們又手動為其添加了一個構造函數。和其它構造函數不同,此構造函數使用右值引用形式的參數,又稱為移動構造函數。并且在此構造函數中,num 指針變量采用的是淺拷貝的復制方式,同時在函數內部重置了 d.num,有效避免了“同一塊對空間被釋放多次”情況的發(fā)生。

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

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

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

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

在實際開發(fā)中,通常在類中自定義移動構造函數的同時,會再為其自定義一個適當的拷貝構造函數,由此當用戶利用右值初始化類對象時,會調用移動構造函數;使用左值(非右值)初始化類對象時,會調用拷貝構造函數。

那么,如果使用左值初始化同類對象,但也想調用移動構造函數完成,有沒有辦法可以實現呢?

默認情況下,左值初始化同類對象只能通過拷貝構造函數完成,如果想調用移動構造函數,則必須使用右值進行初始化。C++11 標準中為了滿足用戶使用左值初始化同類對象時也通過移動構造函數完成的需求,新引入了 std::move() 函數,它可以將左值強制轉換成對應的右值,由此便可以使用移動構造函數。

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

相關文章

  • C++?using?編譯指令與名稱沖突問題

    C++?using?編譯指令與名稱沖突問題

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

    C/C++獲取Windows平臺CPU占用率的方法

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

    c語言經典習題之逆序字符串詳解

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

    C++迭代器失效問題及解決

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

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

    數據庫中存儲的protobuf序列化的內容,有時候查問題想直接解析查看內容。很多編碼在網上很容易找到編解碼工具,但protobuf沒有找到編解碼工具,可能這樣的需求比較少吧,那就自己用C++實現一個,感興趣的可以了解一下
    2023-01-01
  • C語言實現基于控制臺的電子時鐘

    C語言實現基于控制臺的電子時鐘

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

    C++關于/2和>>1的區(qū)別說明

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

    C++ Boost實現數字與字符串轉化詳解

    Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱
    2022-11-11
  • C語言中正切的相關函數總結

    C語言中正切的相關函數總結

    這篇文章主要介紹了C語言中正切的相關函數總結,包括正切和反正切以及雙曲線正切等的函數,需要的朋友可以參考下
    2015-08-08
  • C語言實現三子棋實例代碼

    C語言實現三子棋實例代碼

    大家好,本篇文章主要講的是C語言實現三子棋實例代碼,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01

最新評論

合水县| 南溪县| 松阳县| 米泉市| 临泉县| 呼伦贝尔市| 涪陵区| 浙江省| 宜兴市| 高州市| 宣城市| 长寿区| 滨海县| 南漳县| 株洲市| 绥宁县| 察隅县| 都兰县| 神池县| 高密市| 康马县| 肃北| 海兴县| 察雅县| 阳泉市| 霸州市| 涞源县| 吐鲁番市| 吉林省| 调兵山市| 阜新| 任丘市| 礼泉县| 龙门县| 绥滨县| 靖远县| 沂南县| 林芝县| 安国市| 永德县| 武宣县|