2015-02-17 72 views
9

考慮下面的函數: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 
+0

'w'中的w都是左值(可能被複製爲回報)。主要區別是函數參數,第一個是副本(!),第二個不是。將std :: move應用到第二個函數應該使它(幾乎?)成爲noop。 – 2015-02-17 22:45:50

+3

@MattMcNabb它確實是對的。引用有一個例外,必須有。製作Widget f(Widget&w){return w; }'無聲地移動將是危險的。現在,如果僅僅是左值引用,那麼該異常*可能會好起來,但它僅僅適用於所有不知道從哪裏移出的安全信息。 – hvd 2015-02-17 22:46:09

+0

@hvd'return w;'總是將參數複製到返回值 - 無論它是Widget w',Widget&w'還是'Widget && w'。 (至少,這就是我的編譯器告訴我的)。然後可以將返回值移到它分配的對象中;這一舉動通常會被取消。 – 2015-02-17 22:53:09

回答

5

用於基於當複製省略允許對隱含移動標準,但也有一些例外。複製elision被允許用於不是函數參數或捕獲參數的本地對象。隱式移動添加了作爲函數參數的本地對象。所以它允許它在Widget f(Widget w) { return w; },但不在Widget f(Widget&& w) { return w; },其中w是一個局部變量,但不是本地對象。

在當前不允許的情況下隱式移動是安全的,包括在您的示例中。但是,隱性移動是根據具體情況仔細考慮的,您的示例要麼尚未考慮,要麼尚未被視爲安全。

非常類似的例子Widget f(Widget& w) { return w; }將是不安全:呼叫者做Widget w; f(w);不能指望w默默由編譯器清除出去。

這個非常相似的例子顯示了啓用隱式移動是多麼的冒險,以及爲什麼你必須拼出來,即使它看起來很明顯。涉及「局部變量」的措辭涵蓋Widget&& w也將覆蓋Widget& w。在不安全的情況下進行隱式移動要比隱式移動安全的情況要糟得多,必須絕對確定文字只有覆蓋安全的情況。

+0

我不認爲複製elision在返回函數參數時被允許。 – juanchopanza 2015-02-17 22:58:07

+0

@ hvd:這就是我想了解的:如果它是「不考慮」或「不安全」。在後一種情況下,我想明白爲什麼。 「非常相似」的例子顯然是不安全的。 – Martin 2015-02-17 23:01:24

+1

@juanchopanza糟糕...你說的很對,我的回答是錯誤的。這種例外情況不在複製方面,這是標準需要隱式轉移的另一種情況。將編輯。 – hvd 2015-02-17 23:02:41