轉載請註明出處:http://www.javashuo.com/article/p-qhwzkmqc-gs.html html
pass by value是整包傳遞,無論這個包多大。傳的動做其實是壓到funtion stack memory中。stack memory中有個好處就是Automatic memory management and garbage collection,可是整包傳遞的作法實在不高明。C爲了解決整包傳遞效率低下問題引入pointer,不傳遞整包東西而是改成傳遞整包東西的地址,32爲架構下一個pointer只佔4Byte,速度很快。C++引入reference,其行爲像pointer,可是處理手段更漂亮更高明。不像指針,你能夠把指針的地址打印出來,reference讓人看不到摸不着。reference在底部就是一個pointer,pass by reference就至關於pass by pointer那麼的快。雖然你可能遇到傳單個字符(大小才1Byte),這種狀況下pass by value比pass by reference還快,但大多數狀況,或者一個通用的準者是首選pass by reference.ios
C中pass by pointer,接收者對pointer的更改會影響發送者。C++中pass by reference 也會存在這個問題。若是你不但願接收者修改reference,你能夠加上const限定。程序員
C++ reference主要用途就是傳遞 ,能夠傳遞參數,也能夠傳遞返回值。數組
在函數須要return的時候,優先選擇return by reference。可是能不能return by reference還要視狀況而定。若是你要return的那個東西,事先已經存在過,也就是說已經有一塊memory能夠存放這個東西,那麼OK,你能夠return by reference,速度很快。若是事先沒有memory接收這個東西,那麼你就只能傳回一個local object。有些經驗老道的程序員還會藉助C++中 typename(...)這個特殊語法,返回tmp object加快程序執行效率,這種tmp object的生存週期很短,只有一行代碼。不管是local object仍是tmp object,你都不能return by reference。由於一旦出了function,你reference的那塊memory就被回收了。嚴格意義上說被回收的那段memory是function stack memeory。架構
補充:tmp objectide
C++不容許出現Null reference函數
我的觀點:C/C++聲明一個變量,聲明是不賦值的,屬於弱符號。對於一個不賦值的弱符號而言,若是是全局變量則在編譯階段放在.bss節,;若是是局部變量,也就是auto類型,是在程序運行期間自動分佈於棧內存。總之是沒有開闢內存空間。引用本質上是對一段已經命名的內存空間起個別名。因此對於空引用而言,他就不可能引用一段不存在的內存。C++引用着這種作法和Python很像,Python經過分析一段內存的引用計數來決定是否回收這段內存。固然,C++不會自動幫咱們回收內存,處理好內存是一個程序員的基本素養。this
想一想C在函數中return by pointer的場景spa
returnType *functionName(param list);
__doapl(...)左邊參數是一個pointer,返回值是*ths,是pointer指向的一個東西,也就是object,是value。這裏體現了reference的好處,接收者此案例中是使用reference接收,固然你使用return by value,也就是包傳遞也徹底OK,只是效率上沒有return by reference快。C++也能夠像C同樣return by pointer,可是傳遞着必須作出更改,也就是所傳遞的形式看起來是pointer。指針
注意體會這種思想,reference做用的場景是涉及到傳遞的時候,不管是參數傳遞仍是函數返回值傳遞。
上圖中operator+=返回值是complex& ,其實徹底能夠返回void。由於+=執行完其結果已經放到this裏面了。這樣的確能夠,應對c2 += c1徹底沒問題。
可是返回void的情形沒法應對連續使用+=的狀況,例如c3 += c2 += c1,c2 += c1返回值時void,c3 在調用+=的時候就不符合定義了。返回complex&就能夠。
#include<iostream> int main(int argc, char **argv) { int a = 100; int &b = a; getchar(); return 0; }
引用b 和 a指向同一塊內存
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 int a = 100; 6 int *p = &a; 7 int* &q = p; 8 getchar(); 9 return 0; 10 }
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 int ar[10]; 6 int(&br)[10] = ar; 7 getchar(); 8 return 0; 9 }
#include<iostream> int main(int argc, char **argv) { const int a=10; int &b = a; getchar(); return 0; }
這個代碼在VS 2017下編譯不過。a是個常量(使用const限定),b是個引用,可是b沒有加const限定,他引用a,會有一種嫌疑,即b能夠間接修改a,致使a再也不是常量。因此要想引用常量a,必須使用常引用,代碼以下
#include<iostream> int main(int argc, char **argv) { const int a=10; const int &b = a; getchar(); return 0; }
像這種引用也是能夠的
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 int a=10; 6 const int &b = a; 7 getchar(); 8 return 0; 9 }
分析以下代碼,這裏的引用比較怪異。引用 和 被引用指向的內存不同,這是由於引用了臨時對象的內存。
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 double a=3.14; 6 const int &b = a; 7 getchar(); 8 return 0; 9 }
發現b 和 a並無指向同一塊內存。這是由於開闢了臨時整形,b引用的是臨時整形。這種引用會有潛在風險,萬一被引用的臨時變量被釋放掉(超過做用域),b就引用了一個不存在的東西,程序崩潰。
以下2段代碼也是編譯不過的
代碼1
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 const double a=3.14; 6 int &b = a; 7 getchar(); 8 return 0; 9 }
代碼2
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 double a=3.14; 6 int &b = a; 7 getchar(); 8 return 0; 9 }
緣由:臨時變量都是具備常量性質的,你不能使用一個變量去引用常量,這樣有潛在改變常量的風險
代碼1對應改爲
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 const double a=3.14; 6 const int &b = a; 7 getchar(); 8 return 0; 9 }
代碼2對應改爲
1 #include<iostream> 2 3 int main(int argc, char **argv) 4 { 5 double a=3.14; 6 const int &b = a; 7 getchar(); 8 return 0; 9 }
就沒問題了。