簡體   English   中英

如何在不妨礙RVO的情況下確保移動?

[英]How to ensure moving without impeding RVO?

當從函數返回一個對象時,自C ++ 11以來可能發生以下情況之一,假設定義了move-and-copy-constructors(另請參見本文末尾的示例):

  1. 有資格獲得copy-elision ,編譯器執行RVO。
  2. 它有資格獲得copy-elision,編譯器不執行RVO,但是......
  3. 有資格使用移動構造函數並被移動。
  4. 以上都沒有使用復制構造函數。

對前3個案例的建議不是使用顯式的std::move ,因為無論如何都要執行移動並且可能阻止可能的RVO,例如參見此SO帖子

但是,在4.情況下,顯式的std::move會提高性能。 但是,作為一個既不會閱讀標准也不會閱讀匯編程序的人,需要花費大量時間來區分案例1-3和案例4。

因此,我的問題是否有辦法以統一的方式處理所有上述案例,例如:

  1. RVO不受阻礙(案例1)
  2. 如果未執行RVO,則使用移動構造函數(案例2,3和4)
  3. 如果沒有move-constructor,則copy-constructor應該用作回退。

以下是一些示例,也可以用作測試用例。

所有示例都使用以下helper-class-definition:

struct A{
    int x;
    A(int x_);
    A(const A& a);
    A(A&& a);
    ~A();
};

1.例子: 1.case,RVO執行, 現場演示結果匯編

A callee1(){
    A a(0);
    return a;
}

2.示例: 1.case,RVO執行, 實時演示生成匯編程序

A callee2(bool which){
    return which? A(0) : A(1);
}

3.示例: 2.case,符合copy-elision,RVO未執行, 實時演示生成的匯編程序

A callee3(bool which){
    A a(0);
    A b(1);
    if(which)
      return a;
    else
      return b; 
}

4.示例: 3.case,不符合copy-elision( x是函數參數),但是對於移動, 實時演示生成的匯編程序

A callee4(A x){
    return x; 
}

5.例子: 4.case,沒有copy-elision或者隱式移動(參見這篇SO帖子 ), live-demonstration結果匯編

A callee5(bool which){
    A a(0);
    A b(1);
    return which ? a : b;
}

6.示例: 4.case,沒有copy-elision或隱式移動, live-demonstration得到的匯編程序

A callee6(){
    std::pair<A,int> x{0,1};
    return x.first;
}

什么時候不能進行RVO?

如果滿足以下任何條件,編譯器(通常)無法執行RVO:

  1. 返回哪個局部變量取決於條件(局部變量在條件之前定義,而不是在其中)
  2. 你正在返回一個類,聯合或結構的成員
  3. 你取消引用一個指針來獲取返回值(這包括數組索引)

在情況1中,您應該使用std::move或使用if語句而不是使用三元運算符來編寫代碼。 在案例2中,您必須使用std::move 在案例3中,您還應該明確使用std::move

確保搬遷建設的政策(如果可能)

處理案例1.我們可以通過依賴if語句來返回局部變量而不是三元運算符來確保移動的值:

A whichOne(bool which) {
    A a(0); 
    A b(1); 
    if(which) {
        return a;
    } else { 
        return b; 
    }
}

如果您真的更喜歡使用三元運算符,請在兩個條件std::move明確使用std::move

A whichOne(bool which) {
    A a(0); 
    A b(1); 
    return which ? std::move(a) : std::move(b); 
}

如果我只想移動a而不是b怎么辦? 我們可以通過在條件中顯式構造它來處理這種情況。 在這種情況下,保證構造的值經歷RVO,因為三元的兩側產生prvalue

A whichOne(bool which) {
    A a(0);
    A b(1); 
    return which 
      ? A(std::move(a)) // prvalue move-constructed from a
      : A(b);           // prvalue copy-constructed from b
}

處理案例2和3.這非常簡單:在返回對象的成員時,或者在返回來自數組或指針的引用時使用std::move

暫無
暫無

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

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