函數調用傳值、傳地址與引用的選擇

從函數調用的角度理解三者之間的區別

  傳值:   
  函數參數壓棧的是參數的副本。   
  任何的修改是在副本上作用,沒有作用在原來的變量上。  


  傳指針:   
  壓棧的是指針變量的副本。   
  當你對指針解指針操作時,其值是指向原來的那個變量,所以對原來變量操作。  


  傳引用:   
  壓棧的是引用的副本。由於引用是指向某個變量的,對引用的操作其實就是對他指向的變量的操作。

函數調用傳值、傳地址與引用的選擇

1. 從功能上。按值傳遞在傳遞的時候,實參被複制了一份,然後在函數體內使用,函數體內修改參數變量時修改的是實參的一份拷貝,而實參本身是沒有改變的,所以如果想在調用的函數中修改實參的值,使用值傳遞是不能達到目的的,這時只能使用引用或指針傳遞。例如,要實現兩個數值交換。

void swap(int a int b)

void main(){

int a=1 b=2

swap(a b)

}

這樣,在main()函數中的a b值實際上並沒有交換,如果想要交換隻能使用指針傳遞或引用傳遞,如:

void swap(int *pa int *pb)

void swap(int& ra int& rb)

2.從傳遞效率上。這裏所說傳遞效率,是說調用被調函數的代碼將實參傳遞到被調函數體內的過程,正如上面代碼中,這個過程就是函數main()中的a b傳遞到函數swap()中的過程。這個效率不能一概而論。對於內建的int char short long float等4字節或以下的數據類型而言,實際上傳遞時也只需要傳遞1-4個字節,而使用指針傳遞時在32位cpu中傳遞的是32位的指針,4個字節,都是一條指令,這種情況下值傳遞和指針傳遞的效率是一樣的,而傳遞double long long等8字節的數據時,在32位cpu中,其傳值效率比傳遞指針要慢,因爲8個字節需要2次取完。而在64位的cpu上,傳值和傳址的效率是一樣的。再說引用傳遞,這個要看編譯器具體實現,引用傳遞最顯然的實現方式是使用指針,這種情況下與指針的效率是一樣的,而有些情況下編譯器是可以優化的,採用直接尋址的方式,這種情況下,效率比傳值調用和傳址調用都要快,與上面說的採用全局變量方式傳遞的效率相當。

再說自定義的數據類型,class struct定義的數據類型。這些數據類型在進行傳值調用時生成臨時對象會執行構造函數,而且當臨時對象銷燬時會執行析構函數,如果構造函數和析構函數執行的任務比較多,或者傳遞的對象尺寸比較大,那麼傳值調用的消耗就比較大。這種情況下,採用傳址調用和採用傳引用調用的效率大多數下相當,正如上面所說,某些情況下引用傳遞可能被優化,總體效率稍高於傳址調用。

3. 從執行效率上講。這裏所說的執行效率,是指在被調用的函數體內執行時的效率。因爲傳值調用時,當值被傳到函數體內,臨時對象生成以後,所有的執行任務都是通過直接尋址的方式執行的,而指針和大多數情況下的引用則是以間接尋址的方式執行的,所以實際的執行效率會比傳值調用要低。如果函數體內對參數傳過來的變量進行操作比較頻繁,執行總次數又多的情況下,傳址調用和大多數情況下的引用參數傳遞會造成比較明顯的執行效率損失。

綜合2、3兩種情況,具體的執行效率要結合實際情況,通過比較傳遞過程的資源消耗和執行函數體消耗之和來選擇哪種情況比較合適。而就引用傳遞和指針傳遞的效率上比,引用傳遞的效率始終不低於指針傳遞,所以從這種意義上講,在c++中進行參數傳遞時優先使用引用傳遞而不是指針。

4. 從類型安全上講。值傳遞與引用傳遞在參數傳遞過程中都執行強類型檢查,而指針傳遞的類型檢查較弱,特別地,如果參數被聲明爲 void ,那麼它基本上沒有類型檢查,只要是指針,編譯器就認爲是合法的,所以這給bug的產生製造了機會,使程序的健壯性稍差,如果沒有必要,就使用值傳遞和引用傳遞,最好不用指針傳遞,更好地利用編譯器的類型檢查,使得我們有更少的出錯機會,以增加代碼的健壯性。

這裏有個特殊情況,就是對於多態的情況,如果形參是父類,而實參是子類,在進行值傳遞的時候,臨時對象構造時只會構造父類的部分,是一個純粹的父類對象,而不會構造子類的任何特有的部分,因爲辦有虛的析構函數,而沒有虛的構造函數,這一點是要注意的。如果想在被調函數中通過調用虛函數獲得一些子類特有的行爲,這是不能實現的。

5. 從參數檢查上講。一個健壯的函數,總會對傳遞來的參數進行參數檢查,保證輸入數據的合法性,以防止對數據的破壞並且更好地控制程序按期望的方向運行,在這種情況下使用值傳遞比使用指針傳遞要安全得多,因爲你不可能傳一個不存在的值給值參數或引用參數,而使用指針就可能,很可能傳來的是一個非法的地址(沒有初始化,指向已經delete掉的對象的指針等)。所以使用值傳遞和引用傳遞會使你的代碼更健壯,具體是使用引用還是使用,最簡單的一個原則就是看傳遞的是不是內建的數據類型,對內建的數據類型優先使用值傳遞,而對於自定義的數據類型,特別是傳遞較大的對象,那麼請使用引用傳遞。

6. 從靈活性上。無疑,指針是最靈活的,因爲指針除了可以像值傳遞和引用傳遞那樣傳遞一個特定類型的對象外,還可以傳遞空指針,不傳遞任何對象。指針的這種優點使它大有用武之地,比如標準庫裏的time( )函數,你可以傳遞一個指針給它,把時間值填到指定的地址,你也可以傳遞一個空指針而只要返回值。

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/wzhwho/archive/2010/08/29/5847216.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章