14. 函式返回值為引用?
函式返回值可以是引用嗎?
當然可以,只是在函式返回引用的時候需要注意幾點。以下給出討論!
函式在返回值的時候,會產生一個臨時變數作為函式返回值的副本;而函式在返回引用的時候,不會產生副本!那麼既然是引用,那麼到底是引用誰呢?
首先,我們知道要清楚函式返回引用的幾種常見形式:
1)引用函式的引數,當然該引數(s1、s2)也是一個引用。
const string &shorter_String(const string &s1,const string &s2) { return s1.size()<s2.size()?s1:s2; }
以上函式的返回值是引用型別。無論返回s1或是s2,呼叫函式和返回結果時,都沒有複製這些string物件。簡單的說,返回的引用是函式的引數s1或s2,同樣s1和s2也是引用,而不是在函式體內產生的。
2)不要返回區域性物件的引用,函式體內區域性物件是不能被引用的,因為函式呼叫完區域性物件會被釋放。
const string &mainip(const string &s)
{
string ret=s;
return ret;
}
當函式執行完畢,程式將釋放分配給區域性物件的儲存空間。此時,對區域性物件的引用就會指向不確定的記憶體。
3)在類的成員函式中,返回類物件的引用(不能是函式內定義的類物件(會釋放掉)),一般為this指向的物件,典型的例子是string類的賦值函式。
String& String::operator =(const String &str) //注意與“+”比較,函式為什麼要用引用呢?a=b=c,可以做為左值 { if (this == &str) { return *this; } delete [] m_string; int len = strlen(str.m_string); m_string = new char[len+1]; strcpy(m_string,str.m_string); return *this; }
引用作為返回值,必須遵守以下規則:
(1)不能返回區域性變數的引用。主要原因是區域性變數會在函式返回後被銷燬,因此被返回的引用就成為了"無所指"的引用,程式會進入未知狀態。
(2)不能返回函式內部new分配的記憶體的引用。雖然不存在區域性變數的被動銷燬問題,可對於這種情況(返回函式內部new分配記憶體的引用),又面臨其它尷尬局面。例如,被函式返回的引用只是作為一 個臨時變量出現,而沒有被賦予一個實際的變數,那麼這個引用所指向的空間(由new分配)就無法釋放,造成memory leak(記憶體洩露)。
(3)可以返回類成員的引用,但最好是const。主要原因是當物件的屬性是與某種業務規則(business rule)相關聯的時候,其賦值常常與某些其它屬性或者物件的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它物件可以獲得該屬性的非常 量引用(或指標),那麼對該屬性的單純賦值就會破壞業務規則的完整性。