自己動手理解nrv優化
2010.6.29
燭秋2010.8.20整理
說明:本文整理自:
一、nrv的簡單理解
nrv是named return value的簡稱。nrv優化簡單的說:有一條語句,a a = f();其中f()是乙個函式,函式裡邊申請了乙個a的物件b,然後把物件b返回。在物件返回的時候,一般情況下要呼叫拷貝函式,把函式f()裡邊的區域性物件b拷貝到函式外部的物件a。但是如果用了nrv優化,那就不必要呼叫拷貝建構函式,編譯器可以這樣做,把a的位址傳遞進函式f(),然後不讓f()申請要返回的物件b的空間,用a的位址來代替b的位址,這樣當要返回物件b的時候,就不必要拷貝了,因為b就是a,省去了區域性變數b,省去了拷貝的過程。
二、動手測試
書上得來終覺淺。動手測試才是王道。
測試**如下:
/
#include #include using namespace std;
class a
{public:
a(){ cout<
測試環境:32位機器,vs2005編譯器。
測試部分截圖
圖 1 debug模式下main()函式
圖 2 debug模式下f()函式
圖 3 release模式下 main()函式
圖 4 release模式下f()函式
三、分析
(1)debug模式
分析圖 1和圖 2可以發現在呼叫f()函式時,傳進了乙個引數,這個引數就是拷貝建構函式的目標物件。而拷貝建構函式的源物件就是在f()函式裡邊定義的區域性物件。構造物件的過程是這樣的:首先在main()函式中申請物件b的空間,注意此時沒有構造該物件,僅有位址而已;然後進入f()函式,構造f()函式中的物件a,接著呼叫拷貝建構函式構造main()函式中的物件b,位址是在main()函式時申請的;結束。
(2)release模式
分析圖 3和圖 4可以發現在呼叫f()函式時,通過esi傳遞了外部物件b的位址,在f()函式裡邊沒有申請區域性物件的空間,沒呼叫建構函式(內聯了),只是輸出"construct",也沒呼叫strcpy函式,而是通過暫存器把"zhangsan"拷貝到esi所指向的位址。release模式做了很大的優化!構造物件的過程是這樣的:首先在main()函式申請物件b的空間,注意此時僅有位址而已;然後進入f()函式,構造物件b;結束。
(3)總結
可以這樣理解:debug模式下,給函式傳遞外部變數b的位址,函式內先申請乙個區域性變數a,接著對a操作,最後呼叫拷貝建構函式把a拷貝到外部變數b,結束返回。release模式下,給函式傳遞外部變數b的位址,函式內不申請區域性變數a的空間,把b作為a的空間,接著對a操作,結束返回。
release模式下,區域性變數建構函式的操作還是有的,就是沒有申請空間,通過暫存器拷貝字串"zhangsan"的過程就是在呼叫建構函式,不過看起來被內聯在f()函式裡邊了。可以在f()函式返回之前,區域性變數定義之後增加幾行**,再進行測試。
四、關於測試
1、 如何測試?為了方便測試可以輸出一些字元,然後在od裡使用超級字串查詢外掛程式,方便定位。
2、如何知道有沒有申請空間?看函式入口處有沒有類似於sub esp,xx的指令,在debug模式下會發現f()函式裡邊有申請區域性變數,而release模式下f()函式沒有申請區域性變數。
3、一般情況下,堆疊的區域性變數會採用[ebp-xx]的方式訪問,而通過堆疊傳遞的引數會採用[ebp+xx]的方式訪問。另外要注意在函式採用暫存器傳遞引數,例如:this指標採用ecx暫存器,esi作為外部變數的位址。
NRV優化詳解
大綱 函式返回區域性物件的拷貝的一般實現方式。nrv named return value 優化。nrv優化觸發的疑問。一 函式返回區域性物件的拷貝的一般實現方式 比如有這麼一段函式定義 cpp view plain copy class x x bar 在學習c 語法時,我們知道了。針對 xbar...
NRV優化所帶來的困惑
我們知道要了解編譯器在做什麼,nrv優化應該是乙個無法避免的問題,下面來看乙個例子 include iostream 從這兩個程式的執行來看nrv優化好像並不是那麼如你想象中的好 using namespace std include class text private double arry 1...
自己動手編寫 IronPython IDE
這段時間對ironpython充滿了極大的興趣,學習越深入,越感覺到現有ironpython ide實在不太好用,正好專案中也需要乙個ironpython編輯器,所以就動手做了起來。整整花費了我三天的時間 熬了幾個通宵 總算有了點成果,不過在除錯方面還是存在不足。支援錯誤定位,不過效果不是很好,對開...