2016-08-12 56 views
2
#include<vector>  
struct A { int a[100]; }; 

void foo (const A& a) { 
    std::vector<A> vA; 
    vA.push_back(std::move(a)); // how does move really happen? 
} 

int main() { 
    A a; 
    foo(a); 
} 

上面的代碼編譯得很好。現在,無處不在寫着move避免複製。
以下是我的疑問:std ::移動工作左值引用? std :: move如何在標準容器上工作?

  1. 是否真的move當一個有左值 [無]涉及的工作 - const參考?
  2. 即使使用「右值引用」,如果將對象 插入到上述標準容器中,複製過程如何避免?

例如

void foo (A&& a) { // suppose we invoke this version 
    std::vector<A> vA; 
    vA.push_back(std::move(a)); // how copy is avoided? 
} 
+0

它的工作原理是'std :: move(a)'產生一個'const A &&'(記住'std :: move'只是將它的參數轉換爲一個右值引用)。但是不存在'push_back(const A &&)' - 只有'push_back(const A&)'和'push_back(A &&)' - 這樣的事情,並且第一個被調用,導致複製發生(因爲你不能將一個const rvalue引用綁定到一個非const rvalue引用,但你可以將它綁定到一個常量左值引用)。 – peppe

+0

你是什麼意思,「如何避免副本?」。你問如何實現vector :: push_back(T &&)? –

+0

@SteveJessop,以某種方式是。但我不會在細節上做太多的事情。我的基本問題是,因爲來自外部的A && a可能會在某個位置創建。 'std :: vector'是連續的容器。怎麼可能避免複製呢? – iammilind

回答

8

std::move不採取行動。它實際上將左值引用轉換爲右值引用。在這種情況下,移動的結果是const A &&(這是完全無用的)。

std::vector有一個const A &A &&過載,因此與const A &超負荷將得到選擇,並且在const A &&被隱式強制轉換爲const A &

事實上,std::move可以在const對象調用,奇怪的/出乎意料大多數程序員的行爲,雖然它以某種方式被允許。 (很可能他們有一個用例,或者沒有一個來阻止它)

對於您的示例更具體,類A的移動構造函數將被調用。由於A是POD,因此所有的位都必須移動/複製到A的新實例才能完成複製。

由於標準只規定原始對象必須處於有效狀態未指定的狀態,編譯器可以保留A中的位,並且不必將它們都重置爲0.實際上,大多數編譯器都會保留這些位,因爲更改它們需要額外的指令,這對性能不利。

+0

爲什麼它很奇怪? const T&可以綁定到右值的事實在C++ 11中並不新鮮。 – hvd

+0

讓我澄清這句話,我的意思是存在'const A &&' – JVApen

+2

當你考慮到在C++中,將std :: move添加到一些代碼中否則會導致副本,一般Movable概念的意思是「如果可能的話複製」。它們並不意味着「如果可能,否則不能編譯」。 –