注銷

          注銷

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            112 隨筆 :: 7 文章 :: 18 評論 :: 0 Trackbacks
          不同功能的函數其內部實現各不相同,看起來似乎無法就“內部實現”達成一致的觀點。但根據經驗,我們可以在函數體的“入口處”和“出口處”從嚴把關,從而提高函數的質量。
          ?
          l???????? 【規則6-3-1在函數體的“入口處”,對參數的有效性進行檢查。
          很多程序錯誤是由非法參數引起的,我們應該充分理解并正確使用“斷言”(assert)來防止此類錯誤。詳見6.5節“使用斷言”。
          ?
          l???????? 【規則6-3-2在函數體的“出口處”,對return語句的正確性和效率進行檢查。
          ?? ?如果函數有返回值,那么函數的“出口處”是return語句。我們不要輕視return語句。如果return語句寫得不好,函數要么出錯,要么效率低下。
          注意事項如下:
          (1)return語句不可返回指向“棧內存”的“指針”或者“引用”,因為該內存在函數體結束時被自動銷毀。例如
          ??? char * Func(void)
          ??? {
          ??????? char str[] = “hello world”; // str的內存位于棧上
          ???????
          ??? ?? return str;??????? // 將導致錯誤
          ??? }
          (2)要搞清楚返回的究竟是“值”、“指針”還是“引用”。
          (3)如果函數返回值是一個對象,要考慮return語句的效率。例如???
          ?????? ?????? return String(s1 + s2);
          這是臨時對象的語法,表示“創建一個臨時對象并返回它”。不要以為它與“先創建一個局部對象temp并返回它的結果”是等價的,如
          String temp(s1 + s2);
          return temp;
          實質不然,上述代碼將發生三件事。首先,temp對象被創建,同時完成初始化;然后拷貝構造函數把temp拷貝到保存返回值的外部存儲單元中;最后,temp在函數結束時被銷毀(調用析構函數)。然而“創建一個臨時對象并返回它”的過程是不同的,編譯器直接把臨時對象創建并初始化在外部存儲單元中,省去了拷貝和析構的化費,提高了效率。
          類似地,我們不要將?
          return int(x + y); // 創建一個臨時變量并返回它
          寫成
          int temp = x + y;
          return temp;
          由于內部數據類型如int,float,double的變量不存在構造函數與析構函數,雖然該“臨時變量的語法”不會提高多少效率,但是程序更加簡潔易讀。
          首先來看內部數據類型:
          return int(x+y)
          int temp = x+y;
          return temp;
          的區別:
          反匯編如下:
          ? return ? int(x+y); ? ? ? ? ? ? ? ? ? ? ? mov ? eax,x ?
          ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?add ? eax,y ?
          ? ?
          ? ?
          ? int ? temp ? = ? x ? + ? y; ? ? ? ? ??mov ? eax ? ,x ?
          ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??add ? eax ? ,y ?

          ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mov ? temp,eax ?
          ? ?
          ?
          return ? temp; ? ? ? ? ? ? ? ? ? ? ????? mov ? eax,temp ?
          ?
          可見:對于前者編譯器直接將x+Y的值放如了寄存器eax中,而對于后者我們可以通過紅色反匯編部分,相對前者對復制了2次(從eaxàtemp,再從tempàeax).
          ?
          再看類類型
          return string (x+y)
          string temp = x+y;
          return temp;
          的區別:
          對于前者: 編譯器直接把臨時對象創建并初始化在外部存儲單元中,省去了拷貝和析構的化費,提高了效率
          ?
          138:????? String fun()
          139:????? {
          0040EC70?? push??????? ebp
          0040EC71?? mov???????? ebp,esp
          0040EC73?? push??????? 0FFh
          0040EC75?? push??????? offset __ehhandler$?fun@@YA?AVString@@XZ (004132f2)
          0040EC7A?? mov???????? eax,fs:[00000000]
          0040EC80?? push??????? eax
          0040EC81?? mov???????? dword ptr fs:[0],esp
          0040EC88?? sub???????? esp,58h
          0040EC8B?? push??????? ebx
          0040EC8C?? push??????? esi
          0040EC8D?? push???????edi
          0040EC8E?? lea???????? edi,[ebp-64h]
          0040EC91?? mov???????? ecx,16h
          0040EC96?? mov???????? eax,0CCCCCCCCh
          0040EC9B?? rep stos??? dword ptr [edi]
          0040EC9D?? mov???????? dword ptr [ebp-1Ch],0
          140:
          141:???????? String x;
          0040ECA4?? push??????? 0
          0040ECA6?? lea???????? ecx,[ebp-10h]
          0040ECA9?? call??????? @ILT+20(String::String) (00401019)
          //x 對象 constructor
          0040ECAE?? mov???????? dword ptr [ebp-4],1
          142:???????? String y;
          0040ECB5?? push??????? 0
          0040ECB7?? lea???????? ecx,[ebp-14h]
          0040ECBA?? call??? ????@ILT+20(String::String) (00401019)//y對象constructor
          0040ECBF?? mov???????? byte ptr [ebp-4],2
          143:???????? return String(x+y);
          0040ECC3?? lea???????? eax,[ebp-14h]
          0040ECC6?? push??????? eax
          0040ECC7?? lea???????? ecx,[ebp-10h]
          0040ECCA?? push??????? ecx
          0040ECCB?? lea???????? edx,[ebp-18h]
          0040ECCE?? push??????? edx
          0040ECCF?? call??????? @ILT+25(operator+) (0040101e)//調用operator+
          0040ECD4?? add???????? esp,0Ch
          0040ECD7?? mov???????? dword ptr [ebp-20h],eax
          0040ECDA?? mov???????? eax,dword ptr [ebp-20h]
          0040ECDD?? mov???????? dword ptr [ebp-24h],eax
          0040ECE0?? mov???????? byte ptr [ebp-4],3
          0040ECE4?? mov???????? ecx,dword ptr [ebp-24h]
          0040ECE7?? push??????? ecx
          0040ECE8?? mov???????? ecx,dword ptr [ebp+8]
          0040ECEB?? call??????? @ILT+15(String::String) (00401014) //constructor臨時對象
          0040ECF0?? mov???????? edx,dword ptr [ebp-1Ch]
          0040ECF3?? or????????? edx,1
          0040ECF6?? mov???????? dword ptr [ebp-1Ch],edx
          0040ECF9?? mov???????? byte ptr [ebp-4],2
          0040ECFD?? lea??????? ?ecx,[ebp-18h]
          0040ED00?? call??????? @ILT+5(String::~String) (0040100a)//y對象destructor
          0040ED05?? mov???????? byte ptr [ebp-4],1
          0040ED09?? lea???????? ecx,[ebp-14h]
          0040ED0C?? call??????? @ILT+5(String::~String) (0040100a)//x對象destructor
          0040ED11?? mov???????? byte ptr [ebp-4],0
          0040ED15?? lea???????? ecx,[ebp-10h]
          0040ED18?? call??????? @ILT+5(String::~String) (0040100a) //destructor? 銷毀臨時對象
          0040ED1D?? mov???????? eax,dword ptr [ebp+8]
          144:????? };
          ?
          對于后者: 上述代碼將發生三件事。首先,temp對象被創建,同時完成初始化;然后拷貝構造函數把temp拷貝到保存返回值的外部存儲單元中;最后,temp在函數結束時被銷毀(調用析構函數)。
          138:????? String fun()
          139:????? {
          0040ED80?? push??????? ebp
          0040ED81?? mov???????? ebp,esp
          0040ED83?? push??????? 0FFh
          0040ED85?? push??????? offset __ehhandler$?fun@@YA?AVString@@XZ (004132fb)
          0040ED8A?? mov???????? eax,fs:[00000000]
          0040ED90?? push??????? eax
          0040ED91?? mov???????? dword ptr fs:[0],esp
          0040ED98?? sub???????? esp,5Ch
          0040ED9B?? push??????? ebx
          0040ED9C?? push??????? esi
          0040ED9D?? push??????? edi
          0040ED9E?? lea???????? edi,[ebp-68h]
          0040EDA1?? mov???????? ecx,17h
          0040EDA6?? mov???????? eax,0CCCCCCCCh
          0040EDAB?? rep stos??? dword ptr [edi]
          0040EDAD?? mov???????? dword ptr [ebp-20h],0
          140:
          141:???????? String x;
          0040EDB4?? push??????? 0
          0040EDB6?? lea???????? ecx,[ebp-10h]
          0040EDB9?? call??????? @ILT+20(String::String) (00401019)//x對象constructor
          0040EDBE?? mov???????? dword ptr [ebp-4],1
          142:???????? String y;
          0040EDC5?? push??????? 0
          0040EDC7?? lea???????? ecx,[ebp-14h]
          0040EDCA?? call??????? @ILT+20(String::String) (00401019)?//y對象constructor
          ?
          0040EDCF?? mov???????? byte ptr [ebp-4],2
          143:???????? String temp;
          0040EDD3?? push??????? 0
          0040EDD5?? lea???????? ecx,[ebp-18h]
          0040EDD8?? call??????? @ILT+20(String::String) (00401019)//temp對象constructor
          0040EDDD?? mov???????? byte ptr [ebp-4],3
          144:???????? return temp=x+y;
          0040EDE1?? lea???????? eax,[ebp-14h]
          0040EDE4?? push??????? eax
          0040EDE5?? lea???????? ecx,[ebp-10h]
          0040EDE8?? push??????? ecx
          0040EDE9?? lea???????? edx,[ebp-1Ch]
          0040EDEC?? push??????? edx
          0040EDED?? call??????? @ILT+25(operator+) (0040101e)//調用operator+
          0040EDF2?? add???????? esp,0Ch
          0040EDF5?? mov???????? dword ptr [ebp-24h],eax
          0040EDF8?? mov???????? eax,dword ptr [ebp-24h]
          0040EDFB?? mov???????? dword ptr [ebp-28h],eax
          0040EDFE?? mov???????? byte ptr [ebp-4],4
          0040EE02?? mov???????? ecx,dword ptr [ebp-28h]
          0040EE05?? push??????? ecx
          0040EE06?? lea???????? ecx,[ebp-18h]
          0040EE09?? call??????? @ILT+0(String::operator=) (00401005)??//調用operator=
          0040EE0E?? push??????? eax
          0040EE0F?? mov???????? ecx,dword ptr [ebp+8]
          0040EE12?? call??????? @ILT+15(String::String) (00401014) //constructor臨時對象
          0040EE17?? mov???????? edx,dword ptr [ebp-20h]
          0040EE1A?? or????????? edx,1
          0040EE1D?? mov???????? dword ptr [ebp-20h],edx
          0040EE20?? mov???????? byte ptr [ebp-4],3
          0040EE24?? lea???????? ecx,[ebp-1Ch]
          0040EE27?? call??????? @ILT+5(String::~String) (0040100a)//temp對象destructor
          0040EE2C?? mov???????? byte ptr [ebp-4],2
          0040EE30?? lea???????? ecx,[ebp-18h]
          0040EE33?? call??????? @ILT+5(String::~String) (0040100a)//y對象destructor
          0040EE38?? mov???????? byte ptr [ebp-4],1
          0040EE3C?? lea???????? ecx,[ebp-14h]
          0040EE3F?? call??????? @ILT+5(String::~String) (0040100a)//x對象destructor
          0040EE44?? mov???????? byte ptr [ebp-4],0
          0040EE48?? lea???????? ecx,[ebp-10h]
          0040EE4B?? call??????? @ILT+5(String::~String) (0040100a) //destructor銷毀臨時對象
          0040EE50?? mov???????? eax,dword ptr [ebp+8]
          145:?? ???};
          ?
          可見,兩中return方式都會有臨時對象的產生,而不同在于String temp; retrun temp=x+y方式多了三個步驟.(即紅色注釋), temp對象調用constructor, 調用operator=, temp對象調用destructor.所以說return String(x+y)效率比較高
          ?
          順便問大蝦們個問題 : 這段反匯編中 , 臨時對象是放在什么地方的呀 ??
          ?

          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1394353

          posted on 2006-11-19 10:09 注銷..... 閱讀(230) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 石泉县| 定安县| 台南县| 开江县| 临颍县| 会东县| 高淳县| 额尔古纳市| 收藏| 长宁县| 南澳县| 宁乡县| 永兴县| 长寿区| 铜山县| 龙海市| 沁水县| 大同县| 洪江市| 广平县| 湖南省| 株洲县| 离岛区| 永修县| 岐山县| 黑河市| 廉江市| 临潭县| 富锦市| 驻马店市| 都安| 广平县| 高尔夫| 保定市| SHOW| 泸州市| 曲麻莱县| 龙里县| 德格县| 冷水江市| 罗源县|