剖析——移动构造函数
移動(dòng)構(gòu)造函數(shù)應(yīng)用的場(chǎng)景????
答:有時(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ì)的初衷。
?
例子示下:
#include<string> #include<vector> using namespace std;class String; ostream& operator<<(ostream& out, String& s); class String { public:friend ostream& operator<<(ostream& out, String& s); public:String(const char* data = ""){if (data == NULL){m_data = new char[1];m_data[0] = '\0';}else{m_data = new char[strlen(data) + 1];strcpy(m_data, data);}cout << "constructor execute..." << endl;}String(String &&s)noexcept{cout << "move constructor execute..." << endl;m_data = NULL;this->m_data = s.m_data;s.m_data = NULL;}~String(){cout << this<<"free execute..." << endl;if(m_data != NULL)delete[] m_data;} private:char* m_data; };ostream& operator<<(ostream& out, String& s) {out << s.m_data;return out; } int main() {String s = "hello";vector<String> vs(1);vs.push_back(std::move(s));return 0; }執(zhí)行結(jié)果:
解析運(yùn)行結(jié)果:
1、第一個(gè) “默認(rèn)構(gòu)造函數(shù)” 是因?yàn)関ector<String> vs(1) , 所以事先使用默認(rèn)構(gòu)造函數(shù)構(gòu)造了一個(gè)Test對(duì)象
2、第二個(gè) “默認(rèn)構(gòu)造函數(shù)” 是因?yàn)門est t ,使用默認(rèn)構(gòu)造函數(shù)構(gòu)造了一個(gè)對(duì)象
3、第三個(gè) “移動(dòng)構(gòu)造函數(shù)” 大多數(shù)人會(huì)以為是 vec.push_back(std::move(s)) ,push_back 導(dǎo)致對(duì)象的移動(dòng)而輸出的。具體的原因其實(shí)是由于重新分配內(nèi)存而導(dǎo)致的,我們的 vector 對(duì)象 vs 初始的容量只有 1 ,且里面已經(jīng)有一個(gè)對(duì)象了,就是vector<Test> vs(1)的時(shí)候創(chuàng)建的,所以再向vs里面添加String對(duì)象時(shí),就會(huì)導(dǎo)致vs重新分配內(nèi)存。由于vs中的對(duì)象定義了移動(dòng)構(gòu)造函數(shù)且是可用的(因?yàn)槲覀儗⑵渎暶鳛榱薾oexcept),所以就會(huì)調(diào)用移動(dòng)構(gòu)造函數(shù)將vs中原始的那個(gè)對(duì)象移動(dòng)到新的內(nèi)存中,從而輸出 “移動(dòng)構(gòu)造函數(shù)”。
4、第四個(gè) “移動(dòng)構(gòu)造函數(shù)” 才是因?yàn)镾tring對(duì)象 t 被移動(dòng)到vector 對(duì)象 vs 新的空間而輸出的
5、第五個(gè) “析構(gòu)函數(shù)” 是因?yàn)橹匦路峙鋬?nèi)存后,原來(lái)的內(nèi)存將被銷毀,所以輸出一個(gè)“析構(gòu)函數(shù)”
6、后面三個(gè) “析構(gòu)函數(shù)” 是因?yàn)閳?zhí)行了return 0, 內(nèi)存被釋放,vs 和 s 都被析構(gòu),所以輸出三個(gè) “析構(gòu)函數(shù)
?
注意:
第四行的輸出由 “移動(dòng)構(gòu)造函數(shù)” 變成了 “拷貝構(gòu)造函數(shù)” ,原因是:
由于我們的移動(dòng)構(gòu)造函數(shù)沒(méi)有聲明為noexcept,所以我們的移動(dòng)構(gòu)造函數(shù)就會(huì)被認(rèn)為是可能拋出異常,所以在重新分配內(nèi)存的過(guò)程中,vs對(duì)象就會(huì)使用拷貝構(gòu)造函數(shù)來(lái)“移動(dòng)”對(duì)象(這里說(shuō)的移動(dòng)其實(shí)是拷貝,并不是移動(dòng)),所以就輸出了“拷貝構(gòu)造函數(shù)”。
?
轉(zhuǎn)載于:https://www.cnblogs.com/single-dont/p/11328524.html
總結(jié)
以上是生活随笔為你收集整理的剖析——移动构造函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java 对象重写tostring
- 下一篇: 基于UDP协议的套接字+socketse