[英]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類型的類對象時,可以通過將臨時對象直接構造到目標中來省略復制/移動操作省略的復制/移動
因此,在這兩種情況下(分別是x41
, x51
),您正在體驗復制省略優化效果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.