亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++中的移動構造函數及move語句示例詳解

2020-05-23 13:45:29
字體:
來源:轉載
供稿:網友

前言

本文主要給大家介紹了關于C++中移動構造函數及move語句的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

首先看一個小例子:

#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;}

結果為:

C++,move構造函數,c,移動構造函數,move,構造函數

#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;}

結果為:

C++,move構造函數,c,移動構造函數,move,構造函數

這兩個小程序唯一的不同是調用vc.push_back()將字符串插入到容器中去時,第一段代碼使用了move語句,而第二段代碼沒有使用move語句。輸出的結果差異也很明顯,第一段代碼中,原來的字符串st已經為空,而第二段代碼中,原來的字符串st的內容沒有變化。

好,記住這兩端代碼的輸出結果之間的差異。下面我們簡單介紹一下移動構造函數。

在介紹移動構造函數之前,我們先要回顧一下拷貝構造函數。

我們都知道,C++在三種情況下會調用拷貝構造函數(可能有紕漏),第一種情況是函數形實結合時,第二種情況是函數返回時,函數棧區的對象會復制一份到函數的返回去,第三種情況是用一個對象初始化另一個對象時也會調用拷貝構造函數。

除了這三種情況下會調用拷貝構造函數,另外如果將一個對象賦值給另一個對象,這個時候回調用重載的賦值運算符函數。

無論是拷貝構造函數,還是重載的賦值運算符函數,我記得當時在上C++課的時候,老師再三強調,一定要注意指針的淺層復制問題。

這里在簡單回憶一下拷貝構造函數中的淺層復制問題

首先看一個淺層復制的代碼

#include <iostream>#include <cstring>#include <cstdlib>#include <vector>using namespace std;class Str{ public: char *value; Str(char s[]) { cout<<"調用構造函數..."<<endl; int len = strlen(s); value = new char[len + 1]; memset(value,0,len + 1); strcpy(value,s); } Str(Str &v) { cout<<"調用拷貝構造函數..."<<endl; this->value = v.value; } ~Str() { cout<<"調用析構函數..."<<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對象中的字符串為:"<<b->value<<endl; delete b; return 0;}

輸出結果為:

C++,move構造函數,c,移動構造函數,move,構造函數

首先結果并不符合預期,我們希望b對象中的字符串也是I love BIT但是輸出為空,這是因為b->value和a->value指向了同一片內存區域,當delete a的時候,該內存區域已經被收回,所以再用b->value訪問那塊內存實際上是不合適的,而且,雖然我運行時程序沒有崩潰,但是程序存在崩潰的風險呀,因為當delete b的時候,那塊內存區域又被釋放了一次,兩次釋放同一塊內存,相當危險呀。

我們用valgrind檢查一下,發現,相當多的內存錯誤呀!

C++,move構造函數,c,移動構造函數,move,構造函數

其中就有一個Invalid free 也就是刪除b的時候調用析構函數,對已經釋放掉對空間又釋放了一次。

那么深層復制應該怎樣寫呢?

代碼如下:

#include <iostream>#include <cstring>#include <cstdlib>#include <vector>using namespace std;class Str{ public: char *value; Str(char s[]) { cout<<"調用構造函數..."<<endl; int len = strlen(s); value = new char[len + 1]; memset(value,0,len + 1); strcpy(value,s); } Str(Str &v) { cout<<"調用拷貝構造函數..."<<endl; int len = strlen(v.value); value = new char[len + 1]; memset(value,0,len + 1); strcpy(value,v.value); } ~Str() { cout<<"調用析構函數..."<<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對象中的字符串為:"<<b->value<<endl; delete b; return 0;}

結果為:

C++,move構造函數,c,移動構造函數,move,構造函數

這次達到了我們預想的效果,而且,用valgrind檢測一下,發現,沒有內存錯誤!

C++,move構造函數,c,移動構造函數,move,構造函數

所以,寫拷貝構造函數的時候,切記要注意指針的淺層復制問題呀! 

好的,回顧了一下拷貝構造函數,下面回到移動構造函數上來。

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

下面這個圖,很好地說明了拷貝構造函數和移動構造函數的區別。

C++,move構造函數,c,移動構造函數,move,構造函數

看明白了嗎?

通俗一點的解釋就是,拷貝構造函數中,對于指針,我們一定要采用深層復制,而移動構造函數中,對于指針,我們采用淺層復制。

但是上面提到,指針的淺層復制是非常危險的呀。沒錯,確實很危險,而且通過上面的例子,我們也可以看出,淺層復制之所以危險,是因為兩個指針共同指向一片內存空間,若第一個指針將其釋放,另一個指針的指向就不合法了。所以我們只要避免第一個指針釋放空間就可以了。避免的方法就是將第一個指針(比如a->value)置為NULL,這樣在調用析構函數的時候,由于有判斷是否為NULL的語句,所以析構a的時候并不會回收a->value指向的空間(同時也是b->value指向的空間)

所以我們可以把上面的拷貝構造函數的代碼修改一下:

#include <iostream>#include <cstring>#include <cstdlib>#include <vector>using namespace std;class Str{ public: char *value; Str(char s[]) { cout<<"調用構造函數..."<<endl; int len = strlen(s); value = new char[len + 1]; memset(value,0,len + 1); strcpy(value,s); } Str(Str &v) { cout<<"調用拷貝構造函數..."<<endl; this->value = v.value; v.value = NULL; } ~Str() { cout<<"調用析構函數..."<<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對象中的字符串為:"<<b->value<<endl; delete b; return 0;}

結果為:

 C++,move構造函數,c,移動構造函數,move,構造函數

修改后的拷貝構造函數,采用了淺層復制,但是結果仍能夠達到我們想要的效果,關鍵在于在拷貝構造函數中,最后我們將v.value置為了NULL,這樣在析構a的時候,就不會回收a->value指向的內存空間。

這樣用a初始化b的過程中,實際上我們就減少了開辟內存,構造成本就降低了。

但要注意,我們這樣使用有一個前提是:用a初始化b后,a我們就不需要了,最好是初始化完成后就將a析構。如果說,我們用a初始化了b后,仍要對a進行操作,用這種淺層復制的方法就不合適了。

所以C++引入了移動構造函數,專門處理這種,用a初始化b后,就將a析構的情況。

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

**移動構造函數的參數和拷貝構造函數不同,拷貝構造函數的參數是一個左值引用,但是移動構造函數的初值是一個右值引用。(關于右值引用大家可以看我之前的文章,或者查找其他資料)。這意味著,移動構造函數的參數是一個右值或者將亡值的引用。也就是說,只用用一個右值,或者將亡值初始化另一個對象的時候,才會調用移動構造函數。而那個move語句,就是將一個左值變成一個將亡值。

移動構造函數應用最多的地方就是STL中

給出一個代碼,大家自行驗證使用move和不適用move的區別吧

#include <iostream>#include <cstring>#include <cstdlib>#include <vector>using namespace std;class Str{ public: char *str; Str(char value[]) {  cout<<"普通構造函數..."<<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<<"拷貝構造函數..."<<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<<"移動構造函數..."<<endl;  str = NULL;  str = s.str;  s.str = NULL; } ~Str() {  cout<<"析構函數"<<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;}

總結

以上就是這篇文章的全部內容,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品成a人在线观看| www.日本久久久久com.| 播播国产欧美激情| 国产精品久久久久久久久久小说| 51精品国产黑色丝袜高跟鞋| 久久福利网址导航| 亚洲欧美精品伊人久久| 中文字幕亚洲一区| 精品国产乱码久久久久久虫虫漫画| 国内免费精品永久在线视频| 亚洲第一偷拍网| 亚洲自拍偷拍网址| 国产成人高潮免费观看精品| 日韩av资源在线播放| 亚洲福利视频二区| 久久国产精品影片| 日韩高清有码在线| 亚洲视频视频在线| 亚洲精品久久久久久久久久久久| 久久久精品久久久| 久久精品久久久久久| 国产免费亚洲高清| 色久欧美在线视频观看| 伊人伊成久久人综合网小说| 亚洲电影免费观看高清完整版在线观看| 黄色一区二区三区| 国产亚洲精品一区二区| 亚洲电影av在线| 成人高清视频观看www| 久久国产精品亚洲| 日韩va亚洲va欧洲va国产| 国产成人中文字幕| 色偷偷av一区二区三区乱| 久久精品国产欧美亚洲人人爽| 日韩高清免费观看| 美女精品视频一区| 色偷偷偷亚洲综合网另类| 日韩美女在线观看一区| 久久九九全国免费精品观看| 亚洲视频在线观看免费| 国产在线视频一区| 国产精品丝袜白浆摸在线| 亚洲国产女人aaa毛片在线| 国产亚洲精品久久久| 亚洲第一精品久久忘忧草社区| 久久九九全国免费精品观看| 日韩av手机在线看| 欧美中文在线视频| 日韩av片免费在线观看| 欧美激情精品久久久久久| 成人免费大片黄在线播放| 久久精品在线视频| 亚洲欧美日韩精品久久奇米色影视| 亚洲欧美日韩一区二区三区在线| 亚洲区在线播放| 精品视频久久久久久| 色婷婷久久av| 国产精品网址在线| 久久亚洲国产精品成人av秋霞| 国产精品v日韩精品| 国产精品18久久久久久麻辣| 欧美激情精品久久久久久久变态| 国产精品一二三在线| 日韩在线欧美在线国产在线| 日韩hd视频在线观看| 最新亚洲国产精品| 国产精品∨欧美精品v日韩精品| 久久精品成人欧美大片古装| 日韩久久精品电影| 欧美性猛交xxxx黑人| 日产日韩在线亚洲欧美| 中日韩美女免费视频网站在线观看| 日韩电影免费在线观看中文字幕| 欧美成人久久久| 青青久久av北条麻妃海外网| 亚洲综合中文字幕在线观看| 久久亚洲精品网站| 亚洲欧洲第一视频| 中文字幕精品在线| 国产女人18毛片水18精品| 韩日欧美一区二区| 国产精品露脸av在线| 国产91色在线|| 国模精品视频一区二区三区| 国产精品夜间视频香蕉| 久久天堂av综合合色| 国产精品久久久久久久久久久久久久| 中文字幕欧美日韩| 亚洲男人第一网站| 国产精品女人网站| 亚洲网站视频福利| 国产精品欧美亚洲777777| 51久久精品夜色国产麻豆| 国产91露脸中文字幕在线| 欧美日韩免费网站| 欧美性猛交视频| 日韩亚洲欧美中文在线| 欧美精品在线看| 亚洲日本欧美日韩高观看| 亚洲成人免费在线视频| 91免费欧美精品| 亚洲成人久久网| 欧美在线免费视频| 欧美丝袜一区二区三区| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产69久久精品成人| 中日韩午夜理伦电影免费| 久久亚洲国产成人| 日韩电影中文字幕在线观看| 91久久久国产精品| 欧美激情久久久| 久久精品久久久久久| 欧美xxxx14xxxxx性爽| 一本一本久久a久久精品综合小说| 亚洲人成电影网站色xx| 久久久伊人欧美| 国产精品美女主播在线观看纯欲| 国产亚洲欧美另类中文| 国产有码一区二区| 日韩久久免费视频| 欧美性猛交xxxx黑人猛交| 亚洲人成毛片在线播放| 亚洲精品福利在线观看| 亚洲精品国产精品自产a区红杏吧| 国产成人涩涩涩视频在线观看| www.欧美精品| 亚洲综合在线播放| 亚洲色图综合久久| 亚洲国产女人aaa毛片在线| 亚洲精品国产综合久久| 日韩二区三区在线| 欧美日韩精品中文字幕| 亚洲天堂av电影| 在线观看欧美www| 91国产在线精品| 欧美国产亚洲精品久久久8v| 亲子乱一区二区三区电影| 国产精品爽爽爽| 91精品成人久久| 久久久av亚洲男天堂| 欧美一区二区大胆人体摄影专业网站| 国产精品99久久久久久www| 国产精品久久久久久久久久小说| 亚洲综合精品伊人久久| 欧美一级淫片播放口| 亚洲国产小视频| 国产欧美中文字幕| 欧美另类老女人| 九九热精品在线| 欧美精品精品精品精品免费| 国产视频精品自拍| 日本欧美一级片| 亚洲日韩第一页| 欧美电影免费观看电视剧大全| 91中文字幕在线观看| 自拍视频国产精品| 亚洲国语精品自产拍在线观看| 91色琪琪电影亚洲精品久久| 欧美日在线观看| 亚洲男人天堂2023| 亚洲综合在线中文字幕| 国产一区二区三区久久精品| 亚洲精品有码在线| 成人亚洲激情网|