簡體   English   中英

使用新的移動語義,什么時候不應該在作用域中使用引用?

[英]With new move semantics, when should you not use a reference in scope?

考慮以下代碼,其中foo的簽名為some_type_t foo();

auto const result = foo();    // copy
auto const & result = foo();
auto const && result = foo();

在這種情況下,使用auto const將是一個浪費的副本。 第二種和第三種情況是無需額外副本即可訪問從foo返回的數據的唯一方法。 第二個和第三個是一樣的。

這是另一個片段

auto result = foo();    // copy
auto & result = foo();  // error
auto && result = foo();

在這個片段中,第二種情況不會編譯,因為無法將右值綁定到左值引用。 第一種情況復制結果,而第三種情況直接從foo “獲取”返回值而不進行復制。

考慮到這一點,在聲明范圍內的變量時,您什么時候不會有& 似乎,只要您始終使用std::move(result)訪問結果,擁有參考總是更有益。

與問題的前提相反,這些都不會導致復制或移動:

auto const result = foo();    // (1)
auto const & result = foo();  // (2)
auto const && result = foo(); // (3)
auto result = foo();          // (4)
auto & result = foo();        // (5) error
auto && result = foo();       // (6)

那么有哪些優點/缺點?

(2), (3) 和 (6) 使用生命周期擴展來確保foo()的結果足夠長以供使用。 這在非常簡單的重構下是脆弱的:

auto const & result = std::max(foo(), 1); // compiles, but broken

(3) 和 (6) 依賴於返回值的臨時性質,所以在某種程度上,它們打破了foo封裝。 我將解釋我的意思。 想象一下foo很昂貴,而您希望將值緩存在某處。 然后你會改變foo()以返回一個const some_type_t& 這些選項之間的選擇可以看作是foo的實現細節。 它如何改變初始化:(1)和(4)仍然有效但引入副本,(2)工作相同,並且(3)和(6)不再編譯。

因此,人們必須在某些變化(2)(3)和(6)下靜默破碎,在某些變化(3)和(6)下大聲破碎,以及在變化(1)和(4)下從未破碎但可能更慢之間做出決定. 這取決於正在構建的系統的優先級。 可以想象在系統中,不破壞現有的正確代碼比在重構時避免無聲的額外副本更重要。 在這樣的系統中,(1) 和 (4) 可能是首選。

或者,可以從這個初始化站點的代碼告訴我們的內容的角度來處理它。 如果代碼審查是您的開發過程的一部分,那么這種觀點將更加相關。 (2), (3) 和 (6) 沒有告訴我們關於結果引用的生命周期,因為foo()可能返回一個引用。 所以我們需要更多的上下文。 但是(1)和(4)是明確的關於生命周期的,所以它們給了我們更多的信息。

它是 C++。 我們有很多初始化和資源生命周期的選項,它們都有權衡。

暫無
暫無

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

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