解析C++中臨時(shí)對(duì)象的產(chǎn)生情況
有些臨時(shí)對(duì)象是系統(tǒng)自己產(chǎn)生的,又有一些臨時(shí)對(duì)象卻是因?yàn)榇a的書寫問題而產(chǎn)生的,因?yàn)榕R時(shí)對(duì)象會(huì)額外消耗系統(tǒng)資源,所以編寫代碼的原則就是產(chǎn)生的臨時(shí)對(duì)象越少越好。臨時(shí)對(duì)象一般都是在棧上,所以一般都不會(huì)手動(dòng)去釋放。
為什么要了解臨時(shí)對(duì)象?因?yàn)榕R時(shí)對(duì)象的產(chǎn)生和銷毀都是有成本的,都會(huì)影響程序的執(zhí)行性能和效率,所以如果能有效地減少臨時(shí)對(duì)象的產(chǎn)生,那么無疑意味著程序性能和效率的提升。
一、產(chǎn)生臨時(shí)對(duì)象的情況
1.1 以值的方式給函數(shù)傳遞參數(shù) - 如何優(yōu)化呢
先看如下案例:
class CTempValue { public: int val1; int val2; public: //構(gòu)造函數(shù) CTempValue(int v1 = 0, int v2 = 0) { cout << "調(diào)用構(gòu)造函數(shù)" << endl; val1 = v1; val2 = v2; cout << "val1 = " << val1 << endl; cout << "val2 = " << val2 << endl; } ~CTempValue() { cout << "調(diào)用了析構(gòu)函數(shù)" << endl; } //拷貝構(gòu)造函數(shù) CTempValue(const CTempValue& t) { cout << "調(diào)用拷貝構(gòu)造函數(shù)" << endl; val1 = t.val1; val2 = t.val2; cout << "val1 = " << val1 << endl; cout << "val2 = " << val2 << endl; } int Add(CTempValue tobj) { int tmp = tobj.val1 + tobj.val2; tobj.val1 = 1000; //這里的修改對(duì)外界沒有影響 return tmp; } }; ???????int main() { CTempValue tm(10, 20); //調(diào)用構(gòu)造函數(shù) int Sum = tm.Add(tm); // 這會(huì)調(diào)用拷貝構(gòu)造函數(shù)的執(zhí)行 cout << "Sum = " << Sum << endl; //Sum = 30 cout << "tm.val1 = " << tm.val1 << endl; //tm.val1 = 10 return 0; }
運(yùn)行結(jié)果如下:
調(diào)用構(gòu)造函數(shù)
調(diào)用拷貝構(gòu)造函數(shù)
調(diào)用了析構(gòu)函數(shù)
Sum = 30
tm.val1 = 10
調(diào)用了析構(gòu)函數(shù)
請(qǐng)注意,結(jié)果中調(diào)用了拷貝構(gòu)造函數(shù),為什么調(diào)用CTempValue類的拷貝構(gòu)造函數(shù)呢?
這是因?yàn)檎{(diào)用Add成員函數(shù)時(shí)把對(duì)象tm傳遞給了Add成員函數(shù),此時(shí),系統(tǒng)會(huì)調(diào)用拷貝構(gòu)造函數(shù)創(chuàng)建一個(gè)副本tobj(成員函數(shù)Add的形參),用于在函數(shù)體Add內(nèi)使用,因?yàn)閠m對(duì)象的vall值(tm對(duì)象的vall值仍舊為10)。
形參tobj是一個(gè)局部對(duì)象(局部變量),從程序功能的角度來講,函數(shù)體內(nèi)需要臨時(shí)使用它一下,來完成一個(gè)程序上的一個(gè)功能,它確實(shí)是一個(gè)局部變量,只能在Add函數(shù)體里使用。所以嚴(yán)格意義來講,它又不能稱為一個(gè)真正意義的臨時(shí)對(duì)象,因?yàn)檎嬲呐R時(shí)對(duì)象往往指的是真實(shí)存在,但又感覺不到的對(duì)象(至少從代碼上不能直接看到的對(duì)象)。
但是,對(duì)于目前確實(shí)生成了tobj對(duì)象,并且調(diào)用了類的拷貝構(gòu)造函數(shù),有了復(fù)制的動(dòng)作,就會(huì)影響程序的執(zhí)行效率。
那如何優(yōu)化呢?
我們可以使用引用:
int Add(CTempValue& tobj){}
1.2 類型轉(zhuǎn)換生成的臨時(shí)對(duì)象 - 如何優(yōu)化呢
1.2.1 類型轉(zhuǎn)換生成的臨時(shí)對(duì)象
接下來,我們看下真正意義的臨時(shí)對(duì)象,因?yàn)檫@個(gè)臨時(shí)對(duì)象確實(shí)存在,但是從程序代碼的角度不能直接看到它。
CTempValue sum; sum = 1000;
執(zhí)行一下,程序結(jié)果如下:
調(diào)用構(gòu)造函數(shù)
val1 = 0
val2 = 0
調(diào)用構(gòu)造函數(shù)
val1 = 1000
val2 = 0
調(diào)用了析構(gòu)函數(shù)
調(diào)用了析構(gòu)函數(shù)
在執(zhí)行sum = 1000;系統(tǒng)調(diào)用了一次CTempValue類的構(gòu)造函數(shù)和析構(gòu)函數(shù),這說明系統(tǒng)肯定產(chǎn)生了一個(gè)對(duì)象,但這個(gè)對(duì)象在哪里,通過代碼完全看不到,所以這個(gè)對(duì)象是一個(gè)真正的臨時(shí)對(duì)象。
那么,產(chǎn)生這個(gè)臨時(shí)對(duì)象的原因是什么呢?
是因?yàn)榘?000賦給sum,而sum本身是一個(gè)CTempValue類型的對(duì)象,1000是一個(gè)數(shù)字,那怎么把數(shù)字能轉(zhuǎn)化成CTempValue類型的對(duì)象呢?所以編譯器這里幫助我們以1000為參數(shù)調(diào)用了CTempValue的構(gòu)造函數(shù)創(chuàng)建了一個(gè)臨時(shí)對(duì)象,因?yàn)镃TempValue構(gòu)造函數(shù)的兩個(gè)參數(shù)都有默認(rèn)值,所以這里的數(shù)字1000就頂替了第一個(gè)參數(shù),而第二個(gè)參數(shù)系統(tǒng)就用了默認(rèn)值,所以從1000是可以成功創(chuàng)建出CTempValue對(duì)象的。
為了進(jìn)一步觀察,增加拷貝賦值運(yùn)算符的代碼:
CTempValue& operator=(const CTempValue& tmpv) { cout << "調(diào)用了拷貝賦值運(yùn)算符" << endl; val1 = tmpv.val1; val2 = tmpv.val2; cout << "val1 = " << val1 << endl; cout << "val2 = " << val2 << endl; return *this; }
執(zhí)行程序,看下結(jié)果:
調(diào)用構(gòu)造函數(shù)
val1 = 0
val2 = 0
調(diào)用構(gòu)造函數(shù)
val1 = 1000
val2 = 0
調(diào)用了拷貝賦值運(yùn)算符
val1 = 1000
val2 = 0
調(diào)用了析構(gòu)函數(shù)
調(diào)用了析構(gòu)函數(shù)
總結(jié)sum = 1000;這行代碼系統(tǒng)做了哪些事:
用1000這個(gè)數(shù)字創(chuàng)建了一個(gè)類型為CTempValue的臨時(shí)對(duì)象;調(diào)用拷貝賦值運(yùn)算符把這個(gè)臨時(shí)對(duì)象里面的各個(gè)成員值賦給了sum對(duì)象;銷毀這個(gè)剛剛創(chuàng)建的CTempValue臨時(shí)對(duì)象。
那如何優(yōu)化呢?
可以把main主函數(shù)中剛剛寫的兩行代碼優(yōu)化成下面一行:
CTempValue sum = 1000; //" = " 在這里不是賦值運(yùn)算符,而是定義初始化的概念
運(yùn)行結(jié)果如下:
調(diào)用構(gòu)造函數(shù)
val1 = 1000
val2 = 0
調(diào)用了析構(gòu)函數(shù)
可以看到,系統(tǒng)沒有生成臨時(shí)對(duì)象,所以系統(tǒng)少調(diào)用了一次構(gòu)造函數(shù),少調(diào)用了一次拷貝賦值運(yùn)算符、少調(diào)用了一次析構(gòu)函數(shù)。
1.2.2 隱式類型轉(zhuǎn)換以保證函數(shù)調(diào)用成功
int calc(const string& strsource, char ch) { const char * p = strsource.c_str(); int icount = 0; //......具體的統(tǒng)計(jì)代碼 return icount; } //在main主函數(shù)的代碼如下: int main() { char mystr[100] = "I love China, oh, yeah!"; int result = calc(mystr, 'o'); return 0; }
一個(gè)是char數(shù)組,一個(gè)是const string&,但是這個(gè)函數(shù)就能調(diào)用成功,為什么呢?
當(dāng)然是編譯器幫助我們做了一些事情,解決類型不匹配,那是如何做的呢?
那就是編譯器產(chǎn)生了一個(gè)類型sring的臨時(shí)對(duì)象,這個(gè)臨時(shí)對(duì)象的構(gòu)造方式就是用mystr作為參數(shù),調(diào)用了string的構(gòu)造函數(shù),這樣形參strsoutce就綁定到這個(gè)string臨時(shí)對(duì)象上了。當(dāng)calc函數(shù)返回的時(shí)候,這個(gè)臨時(shí)對(duì)象會(huì)被自動(dòng)銷毀。
C++只會(huì)為const string&(const引用)產(chǎn)生臨時(shí)對(duì)象,不會(huì)為string&(非const)產(chǎn)生臨時(shí)對(duì)象。
1.3 函數(shù)返回值的時(shí)候 - 如何優(yōu)化呢
我們在main主函數(shù)上面加一個(gè)普通的全局函數(shù):
CTempValue Double(CTempValue& ts) { CTempValue tmpm; //這里會(huì)消耗一次構(gòu)造函數(shù)和一次析構(gòu)函數(shù)的調(diào)用 tmpm.val1 = ts.val1 * 2; tmpm.val2 = ts.val2 * 2; return tmpm; //這里會(huì)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù),這表示生成了一個(gè)臨時(shí)對(duì)象 } int main() { CTempValue ts1(10, 20); CTempValue ts2 = Double(ts1); //其實(shí)臨時(shí)對(duì)象接管的就是右值 CTempValue&& ts2 = Double(ts1); }
臨時(shí)對(duì)象就是一種右值
那如何優(yōu)化呢?
CTempValue Double(CTempValue& ts) { return CTempValue(ts.val1 * 2, ts.val2 * 2); }
通過如上的優(yōu)化系統(tǒng)會(huì)調(diào)用一次拷貝構(gòu)造函數(shù),一次析構(gòu)函數(shù)。
二、小結(jié)
(1)寫代碼的時(shí)候,減少臨時(shí)變量的產(chǎn)生。
(2)鍛煉眼神,能夠盡量看出哪些地方可能會(huì)產(chǎn)生臨時(shí)對(duì)象,尤其是一個(gè)函數(shù)只要返回一個(gè)對(duì)象,一般機(jī)會(huì)產(chǎn)生臨時(shí)對(duì)象。
到此這篇關(guān)于解析C++中臨時(shí)對(duì)象的產(chǎn)生情況的文章就介紹到這了,更多相關(guān)C++臨時(shí)對(duì)象內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
重啟后nvidia-smi命令不可執(zhí)行出現(xiàn)“Make?sure?that?the?latest?NVIDIA?
這篇文章主要介紹了重啟后nvidia-smi命令不可執(zhí)行,出現(xiàn)“Make?sure?that?the?latest?NVIDIA?driver?is?installed?and?running.”問題,本文給大家分享最新完美解決方法,需要的朋友可以參考下2022-12-12基于C++實(shí)現(xiàn)的各種內(nèi)部排序算法匯總
這篇文章主要介紹了基于C++實(shí)現(xiàn)的各種內(nèi)部排序算法,非常經(jīng)典,需要的朋友可以參考下2014-08-08基于C語言實(shí)現(xiàn)簡單學(xué)生成績管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了基于C語言實(shí)現(xiàn)簡單學(xué)生成績管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08char str[] 與 char *str的區(qū)別詳細(xì)解析
以下是對(duì)char str[]與char *str的區(qū)別進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下2013-09-09Ubuntu18.04下QT開發(fā)Android無法連接設(shè)備問題解決實(shí)現(xiàn)
本文主要介紹了Ubuntu18.04下QT開發(fā)Android無法連接設(shè)備問題解決實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06