簡體   English   中英

隱藏的移動建築

[英]Hidden move-construction

為什么有時候不會移動構造函數調用? 測試move-semantics (實時代碼)

struct Test {
    int id;
    Test(int id) : id(id) {
        cout << id << "  Test() " << endl;
    }
    ~Test() {
        cout << id << "  ~Test() " << endl;
    }
    Test(const Test &t) : id(t.id) {
        cout << id << "  Test(const Test &t) " << endl;
    }
    Test(Test &&t) : id(t.id) {
        cout << id << "  Test(Test &&t) " << endl;
    }
    Test &operator=(const Test &t) {
        cout << id << "  operator=(const Test &t) " << endl;
        return *this;
    }
    Test &operator=(Test &&t) {
        cout << id << "  operator=(Test &&t) " << endl;
        return *this;
    }
};

void f(Test z) {
    cout << z.id << "  f(Test z) " << endl;
}

int main() {
    f(Test(1));

    Test t(2); f(t);
}

輸出:

1  Test() 
1  f(Test t)               <---// where is move constructor ?!
1  ~Test() 
2  Test() 
2  Test(const Test &t)     <---// copy constructor of t(2)
2  f(Test t) 
2  ~Test() 
2  ~Test()

測試顯示復制構造函數被調用。

但是,在f(Test(1));之后f(Test(1)); 調用函數f而不為Test(1) rvalue對象調用move-constructor。

它是隱式編譯器優化嗎? 或者我錯過了重要的一點?

明確允許編譯器忽略臨時對象的復制(或移動)。 基本上,對象是在預期有效結果的地方構建的。 如果構造函數或析構函數具有副作用,則甚至允許使用此省略。

相關條款是12.8 [class.copy]第31段:

當滿足某些條件時,允許實現省略類對象的復制/移動構造,即使為復制/移動操作選擇的構造函數和/或對象的析構函數具有副作用。 在這種情況下,實現將省略的復制/移動操作的源和目標視為僅僅兩種不同的引用同一對象的方式,並且該對象的銷毀發生在兩個對象的后期時間。沒有優化就被破壞了。 在下列情況下允許復制/移動操作(稱為復制省略)的這種省略(可以組合以消除多個副本):...

基本上可以使用復制省略的情況

  1. return語句時返回臨時變量或局部變量。
  2. throw表達式時拋出臨時變量或局部變量。
  3. 何時復制臨時對象。
  4. 按值捕獲對象時。

可以省略副本的確切條件列於12.8 [class.copy]第31段。

防止復制/移動省略的最簡單方法是將其傳遞給返回合適引用的函數,例如,使用

f(std::move(Test(1)));

應該防止移動省略。

完成此討論。 我們可以通過此選項在gcc中禁用此優化(復制省略):

-fno-elide-constructors

暫無
暫無

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

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