在定義函式時,必須定義傳回值型態,如果函式不傳回值,使用 void
表示不傳回任何數值;若定義了傳回值型態不為 void
,函式最後要使用 return
傳回數值,否則編譯器失敗。
傳回值與函式定義的傳回值型態之間的行為,類似 =
指定時運算式與變數之間的關係,因此也可以定義傳回值型態為指標、lvalue 參考、rvalue 參考等。
如果傳回位址,那麼傳回值型態可定義為指標型態,這代表著記憶體位址在函式執行完畢後,必須仍是有效的,也就是說這通常代表著,函式內動態配置記憶體,例如:
#include <iostream>
using namespace std;
int* makeArray(int m, int initial = 0) {
int *a = new int[m];
for(int i = 0; i < m; i++) {
a[i] = initial;
}
return a;
}
void deleteArray(int* arr) {
delete [] arr;
}
int main() {
int m = 0;
cout << "陣列大小: ";
cin >> m;
int *arr = makeArray(m);
for(int i = 0; i < m; i++) {
cout << "arr[" << i << "] = " << arr[i] << endl;
}
deleteArray(arr);
return 0;
}
執行結果:
陣列大小: 5
arr[0] = 0
arr[1] = 0
arr[2] = 0
arr[3] = 0
arr[4] = 0
如果不是使用 new
來動態配置,在函式中宣告的變數記憶體,在函式執行結束後會自動消毀,傳回位址就沒有意義,編譯器會提出警訊,執行時期往往也會造成存取錯誤。
也可以定義傳回值型態為 lvalue 參考或 rvalue 參考,然而類似地,不該將區域變數以 lvalue 參考傳回,或者將常量以 rvalue 參考傳回,因為函式執行完畢後,區域變數、常量的記憶體就會被回收了。
在定義函式時,定義傳回型態為 lvalue 參考通常是為了效率,例如,以下的 longerStr
,在傳遞引數或傳回值時,都會發生 string
內容的複製:
#include <iostream>
using namespace std;
string longerStr(string s1, string s2) {
return s1.length() > s2.length() ? s1 : s2;
}
int main() {
string s1 = "Justin Lin";
string s2 = "Monica Huang";
string s3 = longerStr(s1, s2);
cout << s3 << endl;
return 0;
}
這只是單純比較 string
的長度,傳回較長的實例,複製內容若是多餘的,可以改為以下:
#include <iostream>
using namespace std;
string& longerStr(string &s1, string &s2) {
return s1.length() > s2.length() ? s1 : s2;
}
int main() {
string s1 = "Justin Lin";
string s2 = "Monica Huang";
string &s3 = longerStr(s1, s2);
cout << s3 << endl;
return 0;
}
C++ 14 開始,在前後文可以推斷型態的情況下,傳回值型態可以使用 auto
,例如:
#include <iostream>
using namespace std;
auto& longerStr(const string &s1, const string &s2) {
return s1.length() > s2.length() ? s1 : s2;
}
int main() {
string s1 = "Justin Lin";
string s2 = "Monica Huang";
auto &s3 = longerStr(s1, s2);
cout << s3 << endl;
return 0;
}
在上例中,C++ 11 必須定義傳回型態為 const string&
,然而 C++ 14 可以使用 auto&
;參數不能使用 auto
自動推斷型態,因為沒有推斷的來源資訊。
類似地,定義傳回值型態為 rvalue 參考,通常也是為了效率。例如:
#include <iostream>
using namespace std;
string&& concat(string &&lhs, string &rhs) {
lhs += rhs;
return std::move(lhs);
}
int main() {
string s = "++";
string result = concat("C", s);
cout << result << endl;
return 0;
}
在這個例子中,引數 "C"
是個常量,參數 lhs
接管了該常量,因為函式執行完之後,lhs
生命周期也就結束,不會再使用,使用 std::move
將 lhs
當成是 rvalue 傳回,因此 lhs
的內容將移動至 result
,而不是複製至 result
,如果最後傳回的 lhs
是個很長的字串,效率上會比較好。