簡體   English   中英

在哪些情況下(const)引用返回值是不安全的?

[英]In which cases is it unsafe to (const) reference a return value?

我傾向於使用以下符號:

const Datum& d = a.calc();
// continue to use d

當calc的結果在堆棧上時,這可以工作,參見http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ 即使編譯器可能在這里優化,但明確避免臨時對象感覺很好。

今天我意識到,內容d成為無效數據被寫入的一員后a 在這種特殊情況下,get函數只是返回對另一個成員的引用,這與寫入完全無關。 像這樣:

const Datum& d = a.get();
// ... some operation ...
a.somedata = Datum2();
// now d is invalid.

同樣,somedata與dget()無關。

現在我問自己:

  1. 哪些副作用可能導致失效?
  2. 將返回值分配給const引用是不是很糟糕? (特別是當我不知道功能的內部)

我的應用程序是單線程的,除了Qt GUI-Thread。

你好像害怕失敗。 那個auto x = some_func(); 將導致一個額外的移動構造超過auto&& x = some_func(); some_func()返回一個臨時對象時。

你不應該。

如果省略失敗,則表示您的編譯器無能力,或者使用坦率的惡意設置進行編譯。 並且你無法在惡意設置或不稱職的編譯器中存活:不稱職的編譯器可以將帶有整數a+=b變成for (int i = 0; i < abs(b); ++i) {if (b>0) ++a; else --a;} for (int i = 0; i < abs(b); ++i) {if (b>0) ++a; else --a;}並且違反標准的iota。

Elision是核心語言功能。 不要因為你不相信它會發生而編寫壞代碼。


當您想要引用函數提供的數據時,應該通過引用捕獲,而不是單獨穩定的數據副本。 如果您不了解函數的返回值的生命周期,則通過引用捕獲根本不安全

即使您知道數據將是穩定的,維護代碼所花費的時間也比編寫代碼要多:閱讀代碼的人必須能夠一目了然地看到您的假設成立。 並且非本地錯誤很糟糕:對您調用的函數進行看似無害的更改不應該破壞您的代碼。


最終的結果是,除非你有充分的理由不去,否則按價值計算。

按值進行操作使您和編譯器更容易推理您的代碼。 它增加了地方。

如果你有充分的理由不這樣做,那么可以參考一下。

根據具體情況,這個好理由可能不一定非常強大。 但它不應該基於一個無能的編譯器的假設。

應該避免過早的悲觀,但應該過早優化。 獲取(或存儲)引用而不是值應該是您在確定性能問題時所做的事情。 編寫干凈,易於理解的代碼。 將復雜性推向緊密編寫的類型,並使外部界面簡潔明了。 按價值取物,因為價值觀與國家脫鈎。


優化是可替代的。 通過使更多代碼更簡單,您可以更輕松地使用(並提高工作效率)。 然后,當你確定部分在性能的問題,你可以付出努力使代碼更快。

一個很好的例子是基礎代碼:基礎代碼(在任何地方使用)很快就會成為性能的一般拖累,如果不是考慮到性能易用性。 在這種情況下,您希望隱藏類型的復雜性,並展示一個簡單易用的外部接口,不需要用戶理解內部。

但代碼在某個隨機函數? 使用值,最容易使用容器和最友好的O符號來執行最昂貴的操作和最簡單的界面。 矢量如果合理(避免過早的悲觀),但不要冒出幾張地圖。

找到占用90%-99%時間的代碼的1%-10%,並快速完成。 如果你的代碼的其余部分具有良好的O符號性能(因此,對於比你測試的更大的數據集,它不會變得驚人地慢),你將處於良好的狀態。 然后開始用荒謬的數據集進行測試,然后找到慢速部分。

哪些副作用可能導致失效?

持有對類的內部狀態的引用(即,相對於延長臨時的生命周期),然后調用任何非const成員函數可能會使引用無效。

將返回值分配給const引用是不是很糟糕? (特別是當我不知道功能的內部)

我會說不好的做法是保持對類實例的內部狀態的引用,改變類實例,並繼續使用原始引用(除非記錄非const函數不會使引用無效)

我不確定我是否正在回答你期望聽到的內容,但是...... const關鍵字與這里的“不安全”無關。 即使您返回非const引用,它也可能變為無效。 const表示不允許修改它。 例如,如果你的get()返回一個const成員或者get()本身被定義為const就像這個const some_refetence_t& get() const { return m_class_member; } const some_refetence_t& get() const { return m_class_member; } 現在關於你的問題:

  1. 哪些副作用可能導致失效?

如果原始值發生變化,可能會有許多副作用。 例如,假設返回的值是對堆上的對象的引用,該對象被刪除...或者在原始值獲得更新時緩存返回的值。 所有這些都是設計問題。 如果按照設計可以進行這樣的情況,那么返回值應該是值(並且在緩存的情況下,它不能被緩存!:))。

  1. 將返回值分配給const引用是不是很糟糕? (特別是當我不知道功能的內部)

一樣。 如果按照設計,您不必修改您獲得的對象(通過引用或按值),而不是最好將其定義為const 一旦你定義為const ,編譯器將確保你不是試圖在代碼中以某種方式修改它。

這是一個知道你的函數返回的問題。 您還應該完全了解返回值類型及其語義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM