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

C++中的移動(dòng)構(gòu)造函數(shù)及move語(yǔ)句示例詳解

 更新時(shí)間:2017年10月06日 11:56:45   作者:青兒哥哥  
這篇文章主要給大家介紹了關(guān)于C++中移動(dòng)構(gòu)造函數(shù)及move語(yǔ)句的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。

前言

本文主要給大家介紹了關(guān)于C++中移動(dòng)構(gòu)造函數(shù)及move語(yǔ)句的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。

首先看一個(gè)小例子:

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

using namespace std;

int main()
{
 string st = "I love xing";
 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é)果為:

 

這兩個(gè)小程序唯一的不同是調(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)有變化。

好,記住這兩端代碼的輸出結(jié)果之間的差異。下面我們簡(jiǎn)單介紹一下移動(dòng)構(gòu)造函數(shù)。

在介紹移動(dòng)構(gòu)造函數(shù)之前,我們先要回顧一下拷貝構(gòu)造函數(shù)。

我們都知道,C++在三種情況下會(huì)調(diào)用拷貝構(gòu)造函數(shù)(可能有紕漏),第一種情況是函數(shù)形實(shí)結(jié)合時(shí),第二種情況是函數(shù)返回時(shí),函數(shù)棧區(qū)的對(duì)象會(huì)復(fù)制一份到函數(shù)的返回去,第三種情況是用一個(gè)對(duì)象初始化另一個(gè)對(duì)象時(shí)也會(huì)調(diào)用拷貝構(gòu)造函數(shù)。

除了這三種情況下會(huì)調(diào)用拷貝構(gòu)造函數(shù),另外如果將一個(gè)對(duì)象賦值給另一個(gè)對(duì)象,這個(gè)時(shí)候回調(diào)用重載的賦值運(yùn)算符函數(shù)。

無(wú)論是拷貝構(gòu)造函數(shù),還是重載的賦值運(yùn)算符函數(shù),我記得當(dāng)時(shí)在上C++課的時(shí)候,老師再三強(qiáng)調(diào),一定要注意指針的淺層復(fù)制問(wèn)題。

這里在簡(jiǎn)單回憶一下拷貝構(gòu)造函數(shù)中的淺層復(fù)制問(wèn)題

首先看一個(gè)淺層復(fù)制的代碼

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

using namespace std;

class Str{
 public:
 char *value;
 Str(char s[])
 {
 cout<<"調(diào)用構(gòu)造函數(shù)..."<<endl;
 int len = strlen(s);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,s);
 }
 Str(Str &v)
 {
 cout<<"調(diào)用拷貝構(gòu)造函數(shù)..."<<endl;
 this->value = v.value;
 }
 ~Str()
 {
 cout<<"調(diào)用析構(gòu)函數(shù)..."<<endl;
 if(value != NULL)
  delete[] value;
 }
};

int main()
{

 char s[] = "I love BIT";
 Str *a = new Str(s);
 Str *b = new Str(*a);
 delete a;
 cout<<"b對(duì)象中的字符串為:"<<b->value<<endl;
 delete b;
 return 0;
}

輸出結(jié)果為:

 

首先結(jié)果并不符合預(yù)期,我們希望b對(duì)象中的字符串也是I love BIT但是輸出為空,這是因?yàn)閎->value和a->value指向了同一片內(nèi)存區(qū)域,當(dāng)delete a的時(shí)候,該內(nèi)存區(qū)域已經(jīng)被收回,所以再用b->value訪問(wèn)那塊內(nèi)存實(shí)際上是不合適的,而且,雖然我運(yùn)行時(shí)程序沒(méi)有崩潰,但是程序存在崩潰的風(fēng)險(xiǎn)呀,因?yàn)楫?dāng)delete b的時(shí)候,那塊內(nèi)存區(qū)域又被釋放了一次,兩次釋放同一塊內(nèi)存,相當(dāng)危險(xiǎn)呀。

我們用valgrind檢查一下,發(fā)現(xiàn),相當(dāng)多的內(nèi)存錯(cuò)誤呀!

 

其中就有一個(gè)Invalid free 也就是刪除b的時(shí)候調(diào)用析構(gòu)函數(shù),對(duì)已經(jīng)釋放掉對(duì)空間又釋放了一次。

那么深層復(fù)制應(yīng)該怎樣寫呢?

代碼如下:

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

using namespace std;

class Str{
 public:
 char *value;
 Str(char s[])
 {
 cout<<"調(diào)用構(gòu)造函數(shù)..."<<endl;
 int len = strlen(s);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,s);
 }
 Str(Str &v)
 {
 cout<<"調(diào)用拷貝構(gòu)造函數(shù)..."<<endl;
 int len = strlen(v.value);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,v.value);
 }
 ~Str()
 {
 cout<<"調(diào)用析構(gòu)函數(shù)..."<<endl;
 if(value != NULL)
 {
  delete[] value;
  value = NULL;
 }
 }
};

int main()
{

 char s[] = "I love BIT";
 Str *a = new Str(s);
 Str *b = new Str(*a);
 delete a;
 cout<<"b對(duì)象中的字符串為:"<<b->value<<endl;
 delete b;
 return 0;
}

結(jié)果為:

 

這次達(dá)到了我們預(yù)想的效果,而且,用valgrind檢測(cè)一下,發(fā)現(xiàn),沒(méi)有內(nèi)存錯(cuò)誤!

 

所以,寫拷貝構(gòu)造函數(shù)的時(shí)候,切記要注意指針的淺層復(fù)制問(wèn)題呀! 

好的,回顧了一下拷貝構(gòu)造函數(shù),下面回到移動(dòng)構(gòu)造函數(shù)上來(lái)。

有時(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ì)的初衷。

下面這個(gè)圖,很好地說(shuō)明了拷貝構(gòu)造函數(shù)和移動(dòng)構(gòu)造函數(shù)的區(qū)別。

看明白了嗎?

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

但是上面提到,指針的淺層復(fù)制是非常危險(xiǎn)的呀。沒(méi)錯(cuò),確實(shí)很危險(xiǎn),而且通過(guò)上面的例子,我們也可以看出,淺層復(fù)制之所以危險(xiǎn),是因?yàn)閮蓚€(gè)指針共同指向一片內(nèi)存空間,若第一個(gè)指針將其釋放,另一個(gè)指針的指向就不合法了。所以我們只要避免第一個(gè)指針釋放空間就可以了。避免的方法就是將第一個(gè)指針(比如a->value)置為NULL,這樣在調(diào)用析構(gòu)函數(shù)的時(shí)候,由于有判斷是否為NULL的語(yǔ)句,所以析構(gòu)a的時(shí)候并不會(huì)回收a->value指向的空間(同時(shí)也是b->value指向的空間)

所以我們可以把上面的拷貝構(gòu)造函數(shù)的代碼修改一下:

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

using namespace std;

class Str{
 public:
 char *value;
 Str(char s[])
 {
 cout<<"調(diào)用構(gòu)造函數(shù)..."<<endl;
 int len = strlen(s);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,s);
 }
 Str(Str &v)
 {
 cout<<"調(diào)用拷貝構(gòu)造函數(shù)..."<<endl;
 this->value = v.value;
 v.value = NULL;
 }
 ~Str()
 {
 cout<<"調(diào)用析構(gòu)函數(shù)..."<<endl;
 if(value != NULL)
  delete[] value;
 }
};

int main()
{

 char s[] = "I love BIT";
 Str *a = new Str(s);
 Str *b = new Str(*a);
 delete a;
 cout<<"b對(duì)象中的字符串為:"<<b->value<<endl;
 delete b;
 return 0;
}

結(jié)果為:

 

修改后的拷貝構(gòu)造函數(shù),采用了淺層復(fù)制,但是結(jié)果仍能夠達(dá)到我們想要的效果,關(guān)鍵在于在拷貝構(gòu)造函數(shù)中,最后我們將v.value置為了NULL,這樣在析構(gòu)a的時(shí)候,就不會(huì)回收a->value指向的內(nèi)存空間。

這樣用a初始化b的過(guò)程中,實(shí)際上我們就減少了開(kāi)辟內(nèi)存,構(gòu)造成本就降低了。

但要注意,我們這樣使用有一個(gè)前提是:用a初始化b后,a我們就不需要了,最好是初始化完成后就將a析構(gòu)。如果說(shuō),我們用a初始化了b后,仍要對(duì)a進(jìn)行操作,用這種淺層復(fù)制的方法就不合適了。

所以C++引入了移動(dòng)構(gòu)造函數(shù),專門處理這種,用a初始化b后,就將a析構(gòu)的情況。

*************************************************************

**移動(dòng)構(gòu)造函數(shù)的參數(shù)和拷貝構(gòu)造函數(shù)不同,拷貝構(gòu)造函數(shù)的參數(shù)是一個(gè)左值引用,但是移動(dòng)構(gòu)造函數(shù)的初值是一個(gè)右值引用。(關(guān)于右值引用大家可以看我之前的文章,或者查找其他資料)。這意味著,移動(dòng)構(gòu)造函數(shù)的參數(shù)是一個(gè)右值或者將亡值的引用。也就是說(shuō),只用用一個(gè)右值,或者將亡值初始化另一個(gè)對(duì)象的時(shí)候,才會(huì)調(diào)用移動(dòng)構(gòu)造函數(shù)。而那個(gè)move語(yǔ)句,就是將一個(gè)左值變成一個(gè)將亡值。

移動(dòng)構(gòu)造函數(shù)應(yīng)用最多的地方就是STL中

給出一個(gè)代碼,大家自行驗(yàn)證使用move和不適用move的區(qū)別吧

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
using namespace std;

class Str{
 public:
 char *str;
 Str(char value[])
 {
  cout<<"普通構(gòu)造函數(shù)..."<<endl;
  str = NULL;
  int len = strlen(value);
  str = (char *)malloc(len + 1);
  memset(str,0,len + 1);
  strcpy(str,value);
 }
 Str(const Str &s)
 {
  cout<<"拷貝構(gòu)造函數(shù)..."<<endl;
  str = NULL;
  int len = strlen(s.str);
  str = (char *)malloc(len + 1);
  memset(str,0,len + 1);
  strcpy(str,s.str);
 }
 Str(Str &&s)
 {
  cout<<"移動(dòng)構(gòu)造函數(shù)..."<<endl;
  str = NULL;
  str = s.str;
  s.str = NULL;
 }
 ~Str()
 {
  cout<<"析構(gòu)函數(shù)"<<endl;
  if(str != NULL)
  {
  free(str);
  str = NULL;
  }
 }
};
int main()
{
 char value[] = "I love zx";
 Str s(value);
 vector<Str> vs;
 //vs.push_back(move(s));
 vs.push_back(s);
 cout<<vs[0].str<<endl;
 if(s.str != NULL)
 cout<<s.str<<endl;
 return 0;
}

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • websocket++簡(jiǎn)單使用及實(shí)例分析

    websocket++簡(jiǎn)單使用及實(shí)例分析

    下面小編就為大家?guī)?lái)一篇websocket++簡(jiǎn)單使用及實(shí)例分析。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-05-05
  • C語(yǔ)言常見(jiàn)的指針筆試題解析

    C語(yǔ)言常見(jiàn)的指針筆試題解析

    在我們學(xué)習(xí)指針之后,應(yīng)該在實(shí)際應(yīng)用中去理解和掌握它,畢竟實(shí)踐才是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),我們以后在找工作的過(guò)程中免不了會(huì)遇到與指針相關(guān)的試題,本篇文章可以幫助我們提前了解一些常見(jiàn)的指針考點(diǎn),需要的可以了解一下
    2022-10-10
  • Vs?Code中C/C++配置launch.json和tasks.json文件詳細(xì)步驟

    Vs?Code中C/C++配置launch.json和tasks.json文件詳細(xì)步驟

    使用VSCode開(kāi)發(fā)C/C++程序,需要配置tasks.json/launch.json,下面這篇文章主要給大家介紹了關(guān)于Vs?Code中C/C++配置launch.json和tasks.json文件的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • C++ vector操作實(shí)現(xiàn)

    C++ vector操作實(shí)現(xiàn)

    這篇文章主要介紹了C++ vector操作實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • C++利用SQLite實(shí)現(xiàn)命令行工具

    C++利用SQLite實(shí)現(xiàn)命令行工具

    這篇文章主要為大家詳細(xì)介紹了一個(gè)基于 C++、SQLite 和 Boost 庫(kù)的簡(jiǎn)單交互式數(shù)據(jù)庫(kù)操作 Shell,該 Shell 允許用戶通過(guò)命令行輸入執(zhí)行各種數(shù)據(jù)庫(kù)操作,感興趣的可以了解下
    2023-11-11
  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生信息管理系統(tǒng)

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • C++中的Qt?QTableView詳解

    C++中的Qt?QTableView詳解

    這篇文章主要介紹了Qt?QTableView詳解,主要包括常用接口,設(shè)置item屬性,右鍵彈出菜單,結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • C++字符串的截取問(wèn)題

    C++字符串的截取問(wèn)題

    這篇文章主要介紹了C++字符串的截取問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Qt中QScrollArea控件的實(shí)現(xiàn)

    Qt中QScrollArea控件的實(shí)現(xiàn)

    QScrollArea是Qt框架中用于提供一個(gè)滾動(dòng)條區(qū)域,允許用戶滾動(dòng)查看比當(dāng)前可視區(qū)域更大的內(nèi)容的控件,本文主要介紹了Qt中QScrollArea控件的實(shí)現(xiàn),感興趣的可以了解一下
    2025-04-04
  • Qt實(shí)現(xiàn)日志文件的滾動(dòng)寫入

    Qt實(shí)現(xiàn)日志文件的滾動(dòng)寫入

    這篇文章主要為大家介紹了如何使用Qt實(shí)現(xiàn)日志文件的滾動(dòng)寫入功能,在日志文件達(dá)到10MB時(shí)創(chuàng)建新的日志文件,并且在總?cè)罩疚募笮∵_(dá)到10GB時(shí)開(kāi)始覆蓋最早的日志文件,需要的可以參考下
    2024-11-11

最新評(píng)論

阿鲁科尔沁旗| 绥棱县| 英德市| 吉水县| 同仁县| 广昌县| 宜川县| 西林县| 贵阳市| 子洲县| 太谷县| 大安市| 扶余县| 沛县| 永丰县| 南召县| 陆河县| 奇台县| 酒泉市| 旅游| 马公市| 开阳县| 泰宁县| 仙桃市| 台山市| 平阳县| 青田县| 锡林浩特市| 绍兴县| 琼中| 丰都县| 上饶市| 焉耆| 白城市| 潞西市| 鸡西市| 富源县| 邳州市| 柞水县| 沂水县| 白银市|