函式呼叫傳值 傳位址與引用的選擇

2021-05-24 22:25:54 字數 2416 閱讀 9774

從函式呼叫的角度理解三者之間的區別

傳值:   

函式引數壓棧的是引數的副本。   

任何的修改是在副本上作用,沒有作用在原來的變數上。  

傳指標:   

壓棧的是指標變數的副本。   

當你對指標解指標操作時,其值是指向原來的那個變數,所以對原來變數操作。  

傳引用:   

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

函式呼叫傳值、傳位址與引用的選擇

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( )函式,你可以傳遞乙個指標給它,把時間值填到指定的位址,你也可以傳遞乙個空指標而只要返回值。

傳值呼叫與傳位址呼叫(傳引用)

c c 中引數傳遞有兩種方式,傳值或傳位址 傳引用 通常我們要在被呼叫函式中改變乙個變數的值就需要傳位址呼叫方式,例如 void swap by value int a,int b void swap by ptr int pa,int pb int main int argc,char argv ...

傳值 傳引用 傳位址

1.值傳遞 形參是實參的拷貝,改變形參的值並不會影響外部實參的值。從被呼叫函式的角度來說,值傳遞是單向的 實參 形參 引數的值只能傳入,不能傳出。當函式內部需要修改引數,並且不希望這個改變影響呼叫者時,採用值傳遞。void swap int a,int b 呼叫 int x,y swap x,y 實...

傳值 傳位址 傳引用 的區別

傳值 傳位址 傳引用 1 傳值 優點 函式的 不會影響外部的實參 可讀性較高 缺點 傳參效率低 不能通過形參改變實參 對實參有保護作用 void swap int x,int y 2 傳位址 優點 傳參效率高 傳位址只需要4個位元組 確定 傳值變數大小不確定,有可能佔很大空間 可以通過形參改變實參 ...