考慮下面的函數:Return語句異常
Widget f(Widget w) {
return w;
}
假設Widget
同時實現複製和移動的構造,根據C++標準,w
必須被視爲在返回語句右值對象,如果編譯器不考慮複製elision一個更好的選擇。
在另一方面,考慮下面的版本:
Widget f(Widget&& w) {
return w;
}
至於對面的第一個版本,根據Effective Modern C++
Item 25
,筆者似乎暗示返回w
肯定會調用拷貝構造函數。換句話說,他建議返回std::move(w)
,以便使編譯器使用(可能更快)移動構造函數。
你能解釋一下爲什麼f()
採取Widget&&
作爲參數的第二個版本是不等同於第一個版本採取Widget
由值相對於構造被稱爲return語句,也考慮到在雙方的身體表達式w
的功能是指lvalue
?
完整的示例演示行爲:
#include <iostream>
struct Widget
{
Widget() { std::cout << "constructed" << std::endl; }
~Widget() { std::cout << "destructed" << std::endl; }
Widget(const Widget&) { std::cout << "copy-constructed" << std::endl; }
Widget(Widget&&) { std::cout << "move-constructed" << std::endl; }
};
Widget
f1(Widget w)
{
return w;
}
Widget
f2(Widget&& w)
{
return w;
}
int
main()
{
f1(Widget {});
std::cout << std::endl;
f2(Widget {});
}
輸出:
constructed
move-constructed
destructed
destructed
constructed
copy-constructed
destructed
destructed
'w'中的w都是左值(可能被複製爲回報)。主要區別是函數參數,第一個是副本(!),第二個不是。將std :: move應用到第二個函數應該使它(幾乎?)成爲noop。 – 2015-02-17 22:45:50
@MattMcNabb它確實是對的。引用有一個例外,必須有。製作Widget f(Widget&w){return w; }'無聲地移動將是危險的。現在,如果僅僅是左值引用,那麼該異常*可能會好起來,但它僅僅適用於所有不知道從哪裏移出的安全信息。 – hvd 2015-02-17 22:46:09
@hvd'return w;'總是將參數複製到返回值 - 無論它是Widget w',Widget&w'還是'Widget && w'。 (至少,這就是我的編譯器告訴我的)。然後可以將返回值移到它分配的對象中;這一舉動通常會被取消。 – 2015-02-17 22:53:09