2010-07-09 121 views
11

我想了解返回const引用是否有任何好處。我有一個階乘函數,通常是這樣的:我假設會有的性能提升,當我們路過const參考C++通過Const引用並通過Const返回引用

unsigned long factorial(unsigned long n) 
{ 
    return (n == 0) ? 1 : n * factorial(n - 1); 
} 

,我們返回const參考......但const -correctness 總是混淆了我。

const unsigned long & factorial(const unsigned long& n) 
{ 
    return (n == 0) ? 1 : n * factorial(n - 1); 
} 

是否有效返回const參考?此外,有人可以告訴我:這有益嗎?

+0

當返回值超出範圍時(即在函數結束時)會發生什麼?我的猜測是參考指向無效內存。 – robinjam 2010-07-09 22:34:24

+1

通過const引用傳遞'long'不太可能有利於按值傳遞它。一般來說,這是針對具體實現的,但在我能想到的所有體系結構中,「long」和「long」都將表示爲32位數量,或者兩者都是64位。因此,您複製相同數量的數據,但現在調用方必須計算地址(這意味着它也必須有本地數據,而不是隻保留在寄存器中),並且被調用方必須取消引用。充其量,該函數將被內聯,並且優化器將放棄參考。 – 2010-07-09 22:41:22

+0

所以我很安全,如果我只是使返回和輸入參數常量(沒有引用,只是const值)。 – Kiril 2010-07-09 22:44:17

回答

9

這是無效的。您不能返回引用一個局部變量。

MSVS C++編譯器,甚至給出了以下警告:

main.cc : warning C4172: returning address of local variable or temporary 

不甚清楚GCC,但可能的結果將是一樣的。

+0

好的,但可以肯定的是,假定有效的優化是使輸入參數爲const引用,因爲我聽說通過引用爲內置類型(例如long)傳遞const沒有太大的好處。我應該至少使返回類型常量(沒有參考)? – Kiril 2010-07-09 22:40:44

+3

經驗法則是:當您知道類型時 - 按值傳遞基元,傳遞按值封裝單個基元的類,通過const引用傳遞其他所有內容。對於不透明的第三方類,告訴他們的文檔告訴你做什麼(例如迭代器 - 按值傳遞)。當你事先不知道類型(例如它是一個模板類型參數)時,通過const引用並希望優化器將它剝離到不需要的地方:) – 2010-07-09 22:48:31

+0

@Lirik我個人使用'const'時只使用'const '引用和只在類中。否則,他們根本沒有意義。關於優化 - 優化和配置文件。這裏的參考(在彙編代碼中)有時會使事情變得更好,有時甚至更糟。您可能也對此感興趣:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value – 2010-07-09 22:50:35

6

const引用在此處不正確 - 您正在返回一個對局部變量的引用 - 這裏是一個未命名的臨時文件,可能是1n * factorial(n - 1)的結果。因爲引用是函數中的局部變量,所以當引用到達調用方時,該局部變量已經超出範圍,並且是無效的。

將一個常量引用返回到您希望避免複製到的大型結構類型,以便引用在該函數的退出後仍然存在。通常,這意味着返回一個參數或一個成員變量(在類的情況下)的引用。

8

如果值的大小很小,const引用不會快於值。在這種情況下,值的類型是long,這是IMO小(例如4到8字節):所以const引用將不會更快。實際上它可能會比較慢,因爲要獲得引用的值,編譯器可能需要發出將引用引用的代碼(如解引用指針)。

鑑於參考是像指針一樣實現(內部),我希望從傳遞引用中獲得比傳遞值更好的性能,當值的大小大於指針的大小時(假設它是甚至合法地傳遞一個引用:對一個超出範圍的局部變量的引用是不合法的)。

+2

對內部變量*的指針/引用對於表達式,這就是爲什麼std :: string的.c_str()和operator =有效。這也是爲什麼const char * monkey = myStr.c_str();那麼在代碼的其他地方使用指針'猴子'是一個壞主意。 – 2010-11-16 13:16:00

1

可能但我永遠不會那樣做。爲什麼?

因爲這是讓您的代碼不可讀的好方法

此外,編譯器將優化它沒有這個黑客。

此外,你有沒有其他「瓶頸」來優化你的程序?
我的意思是,如果你將這部分代碼放在程序集中,你會發現傳遞函數的值和得到的結果僅僅是一些操作碼。怎麼樣?
那麼,一個32位整數將適合一個寄存器。快如「mov eax,...」。
另一方面,你的程序可能有其他設計/算法問題,可能會優化...除非它像「世界你好」這樣簡單的程序。

所以,要做到這一點並不是我想做的事情,歡迎所有人來挑戰我。

+0

+1'讓代碼不可讀的好方法',並真正打破IMO。我曾參與過這樣的項目,相信我會造成不幸:-( – 2010-11-16 13:12:10

+0

)這個問題清楚地表明,它不是關於程序代碼優化(或可讀性),而是關於*理解* const引用及其用法,沒有證據,我不相信「編譯器會優化它」。你的可讀性是正確的 - 但有時候你必須做你應該做的事情,特別是像C++這樣的朗讀。 – Kissaki 2012-05-23 19:44:54

3

通過const引用返回的唯一情況是,如果您正在返回的對象將超出函數調用*(例如返回調用該函數的類的成員),甚至在這種情況下,是否應該這樣做是可疑的,因爲這將允許兩個不同的調用者訪問相同的內存位置,如果使用多個線程,這會使事情成爲一個噩夢來修復。

*注意:在你的情況下,你正在返回的項目是一個本地變量,因此將不會超過函數調用。因此你提供的代碼調用了惡意的未定義行爲。