2010-06-06 49 views
5

我嘗試下面的代碼:通行證臨時對象函數,採用指針

#include<iostream> 
#include<string> 
using namespace std; 

string f1(string s) 
{ 
    return s="f1 called"; 
} 

void f2(string *s) 
{ 
    cout<<*s<<endl; 
} 

int main() 
{ 
    string str; 
    f2(&f1(str)); 
} 

但是這個代碼不編譯。
我認爲是:f1按值返回,所以它創建了臨時的,我正在將其中的地址傳遞給f2。
現在請解釋我在哪裏我想錯了?

回答

5

一元&取左值(或函數名稱)。函數f1()不返回一個左值,它返回一個右值(對於返回值的函數,除非它返回一個引用,它的返回值是一個右值),所以一元&不能應用於它。

+0

但我可以像這樣使用f1(): f1(str)=「happy」; 這裏我使用臨時值作爲l值。 – 2010-06-06 19:29:15

+4

快樂米塔爾,單詞左值可能有點令人困惑 - 它不再意味着「可以站在任務左側的價值」。當你使用'='運算符時,你實際上正在調用字符串對象的成員函數。您可以使用rvalues的成員。 – avakar 2010-06-06 19:31:48

+0

那麼如果字符串有一個明確的運算符&{return this;}會發生什麼? – user168715 2010-06-06 19:50:55

1

你的程序不能編譯,因爲f1有一個參數,你沒有傳遞任何消息。

此外,從函數返回的值是一個右值,不能取其地址。

+0

哦......我的不好。 但它仍在發出警告:「以臨時地址」 – 2010-06-06 19:25:46

+1

快樂米塔爾,是的,因爲它是一個右值。想象一下函數返回一個「int」而不是「string」,它可能更明顯 - 返回的值不需要任何相應的內存位置。 – avakar 2010-06-06 19:28:32

1

試試這個:

int main() 
{ 
    string str; 
    string str2 = f1(str); // copy the temporary 
    f2(&str2); 
} 
+1

這是一個不必要的副本。 (_如果你不介意不必要地複製字符串,爲什麼還要用C++呢?)如果你將一個右值綁定到一個'const'引用,那麼右值的生命週期將被擴展到引用的生命週期的末尾。所以'const std :: string&str2 = f1(str);'是你想要的。 – sbi 2010-06-06 20:46:32

+0

@sbi:我的例子和他的一樣,比任何現實世界的代碼都簡單得多。 – egrunin 2010-06-06 21:52:01

+1

請注意,你的答案是教人們如何去做他們還不知道的事情。即使你只是省略了一些,因爲它與你的論點無關,但其他人可能仍然會從中挑出一個錯誤的習慣。 – sbi 2010-06-06 23:11:30

3

它可以創建(並通過)一個指向臨時對象,假設你知道你在做什麼。但是,它應該以不同的方式完成。

返回值爲非引用類型的函數返回右值。禁止在C++中使用內置的一元運算符&作爲右值。它需要一個左值。

這意味着,如果你想獲得一個指向臨時對象的指針,你必須以其他方式來完成。例如,作爲兩行序列

const string &r = f1(str); 
f2(&r); 

這也可以通過使用流延

f2(&(const string &) f1(str)); 

在上述f2功能這兩種情況下應該接受一個const string *參數被摺疊成單行。只要一個string *就像在你的情況下是行不通的,除非你拋棄了參數中的常量(這會使整個事情變得比現在更醜陋)。儘管如果內存服務於我,在這兩種情況下,都不能保證引用是附加到原始臨時文件而不是複製文件。

請記住,雖然創建臨時對象的指針是一個相當可疑的做法,因爲如果顯而易見的生命期問題。通常你應該避免需要這樣做。