簡體   English   中英

作為參數的臨時T是否應該在C ++ 11中調用T(const T&)或T(T &&)?

[英]Should a temporary T, as a parameter, invoke T(const T&) or T(T&&) in C++11?

所以,代碼第一:

#include <iostream>
#include <utility>

struct X{
    int i;
    void transform(){}
    X() :i(0){std::cout<<"default\n";}
    X(const X& src): i(src.i){std::cout<<"copy\n";}
    X(X&& msrc) :i(msrc.i){msrc.i=0;std::cout<<"move\n";}
};

X getTransform(const X& src){
    X tx(src);
    tx.transform();
    return tx;
}

int main(){

    X x1;// default
    X x2(x1); // copy
    X x3{std::move(X{})}; // default then move
    X x41(getTransform(x2)); // copy in function ,then what?
    X x42(std::move(getTransform(x2))); // copy in funciton, then move
    X x51( (X()) );//default, then move? or copy?
      // extra() for the most vexing problem
    X x52(std::move(X())); //default then move
    std::cout<<&x41<<"\t"<<&x51<<std::endl;
}

然后從cygwin + gcc 4.8.2開始輸出C ++ 11功能:

default
copy
default
move
copy
copy
move
default
default
move
0x22aa70        0x22aa50

我不太明白的是x41和x51的行。 對於x41,是否應該從函數調用返回的臨時調用移動構造函數或副本? 同樣的問題x51。
第二個問題是,通過查看輸出,x41和x51的結構沒有調用任何定義的構造函數,但是對象在它們駐留在內存中時清楚地創建。 怎么會這樣?

一個未命名的對象自然地比const&更好地匹配&&
否則移動語義將無法工作。

現在,對默認/復制/移動構造函數的調用較少,然后人們可能天真地期望,因為有一個允許復制橢圓的特殊規則,而不考慮可觀察的行為(否則必須通過優化保留):

12.8復制和移動物體§31

當滿足某些條件時, 允許實現省略類對象的復制/移動構造,即使該對象的復制/移動構造函數和/或析構函數具有副作用 在這種情況下,實現將省略的復制/移動操作的源和目標視為僅僅兩種不同的引用同一對象的方式,並且該對象的銷毀發生在兩個對象的后期時間。在沒有優化的情況下銷毀.123在下列情況下允許復制/移動操作(稱為復制省略)的這種省略(可以合並以消除多個副本):
但是,如果從函數返回並直接用於初始化相同類型的對象,則將省略該移動。
- 具有類返回類型的函數的return語句中,當表達式是具有與函數返回類型相同的cv-unqualified類型的非易失性自動對象(除函數或catch子句參數之外)的名稱時,通過將自動對象直接構造到函數的返回值中,可以省略復制/移動操作。
- 當一個未綁定到引用 (12.2) 的臨時類對象被復制/移動到具有相同cv-nonqualified類型的類對象時,可以通過將臨時對象直接構造到該對象中來省略復制/移動操作。省略的復制/移動的目標。
- [...還有2個用於異常處理]

所以,瀏覽你的清單:

X x1;// default
// That's right
X x2(x1); // copy
// Dito
X x3{std::move(X{})}; // default then move
// Yes. Sometimes it does not pay to call `std::move`
X x41(getTransform(x2)); // copy in function ,then what?
// Copy in function, copy to output, move-construction to x41.
// RVO applies => no copy to output, and no dtor call for auto variable in function
// Copy ellision applies => no move-construction nor dtor of temporary in main
// So, only one time copy-ctor left
X x42(std::move(getTransform(x2))); // copy in funciton, then move
// `std::`move` is bad again
X x51( (X()) );//default, then move? or copy? // extra() for the most vexing problem
// Copy-elision applies: default+move+dtor of temporary
// will be optimized to just default
X x52(std::move(X())); //default then move
// And again `std::`move` is a pessimization

我認為使用static_cast可能會避免綁定臨時,這意味着移動可以被省略,但沒有這樣的運氣: 1376。static_cast of temporary to rvalue reference感謝@dyp發掘此問題

我認為這只是簡單的返回值優化。你可以在X tx(src);的函數內創建一個副本X tx(src); ,然后這個局部變量剛剛返回主。 在語義上作為副本,但實際上省略了復制操作。

正如其他人所說,也可以省略移動。

根據標准§12.8[ 復制和移動類對象 ]

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

  • 在具有類返回類型的函數的return語句中 ,當表達式是具有與函數返回類型相同的cvunqualified類型的非易失性自動對象(函數或catch子句參數除外)的名稱時, 副本通過將自動對象直接構造到函數的返回值中,可以省略/ move操作。

  • 當一個未綁定到引用(12.2)的臨時類對象被復制/移動到具有相同cv-nonqualified類型的類對象時,可以通過將臨時對象直接構造到目標中來省略復制/移動操作省略的復制/移動

因此,在這兩種情況下(分別是x41x51 ),您正在體驗復制省略優化效果。

暫無
暫無

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

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