142
阿裏雲
技術社區[雲棲]
C++參數傳遞方式
C++中的參數傳遞有三種方式:傳遞變量名,傳遞指針,傳遞引用。即值傳遞,指針傳遞和引用傳遞。
1.將變量名作為形參和實參
這種情況下傳給形參的是變量的值,傳遞是單向的,就是說如果在執行函數期間形參的值發生變化,並不會傳回給實參,這就是所謂的值傳遞。因為在調用函數期間,形參和實參並不是同一個存儲單元。簡單示例如下:
07
|
int _tmain( int argc,
_TCHAR* argv[])
|
11
|
void swap( int , int ); //參數為整型變量
|
15
|
cout<< "i=" <<i<< ",j=" <<j<<endl;
|
19
|
cout<< "i=" <<i<< ",j=" <<j<<endl;
|
27
|
void swap( int a, int b){ //形參為整型變量
|
2.傳遞變量指針
形參是指針變量,實參是一個變量的地址,調用函數時,形參(指針變量)指向實參變量單元。這種方式還是“值傳遞”,隻不過實參的值是變量的地址而已,在函數中改變的不是實參的值(即改變不到地址,這種改變也是影響不到實參的),而是實參地址所指向的變量的值。示例:
05
|
int _tmain( int argc,
_TCHAR* argv[])
|
09
|
void swap( int *, int *); //參數為整型指針變量
|
13
|
cout<< "i=" <<i<< ",j=" <<j<<endl;
|
17
|
cout<< "i=" <<i<< ",j=" <<j<<endl;
|
25
|
void swap( int *p1, int *p2){ //形參為整型指針變量
|
3.引用傳遞
引用形參是把實參的地址傳遞給形參(引用變量),從而是形參的地址取實參的地址,從而達到形參與實參共享同一單元的方式,這就是地址傳值方式。
方式2中傳遞指針變量需要額外開辟一塊內存單元,內容為地址。而方式3不是一個獨立變量,不需要獨占內存單元。而且調用使用引用形參的函數時,實參不必用函數的地址,而是直接使用變量名。係統向形參傳遞的是實參的地址而不是實參的值。
這三種方式有什麼區別呢?
1.從功能上。按值傳遞在傳遞的時候,實參被複製了一份,然後在函數體內使用,函數體內修改參數變量時修改的是實參的一份值拷貝,而實參本身是沒有改變的(例如上麵的示例1),所以如果想在調用的函數中修改實參的值,使用值傳遞是不能達到目的的,這時隻能使用引用或指針傳遞。
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*時它幾乎不檢查,隻要是指針編譯器就認為是合法的。所以導致程序的健壯性下降。如果沒有必要,就使用值傳遞和引用傳遞,最好不用指針傳遞,更好地利用編譯器的類型檢查,使得我們有更少的出錯機會,以增加代碼的健壯性。
5.從參數檢查上講。一個健壯的函數,總會對傳遞來的參數進行參數檢查,保證輸入數據的合法性,以防止對數據的破壞並且更好地控製程序按期望的方向運行,在這種情況下使用值傳遞比使用指針傳遞要安全得多,因為你不可能傳一個不存在的值給值參數或引用參數,而使用指針就可能,很可能傳來的是一個非法的地址(沒有初始化,或者指向已經delete掉的對象的指針等)。所以使用值傳遞和引用傳遞會使你的代碼更健壯,具體是使用引用還是使用,最簡單的一個原則就是看傳遞的是不是內建的數據類型,對內建的數據類型優先使用值傳遞,而對於自定義的數據類型,特別是傳遞較大的對象,那麼請使用引用傳遞。
6.從靈活性上來說。無疑,指針是最靈活的,因為指針除了可以像值傳遞和引用傳遞那樣傳遞一個特定類型的對象外,還可以傳遞空指針,不傳遞任何對象。這算是指針的優點了。
在參數傳遞過程中配合使用較多的const關鍵字,可以保證參數不被修改。就像我找人幫我數錢,我肯定不會希望我的錢變少了,所以使用const修飾變量,使其指向一個const對象。需要注意下參數順序。當同個函數名有不同參數時,如果有相同的參數盡量要把參數放在同一位置上,以方便其他函數調用。
最後更新:2017-04-03 22:15:47