2013-07-09 50 views
3

std::move可用於在隱式地不允許移動時允許移動語義(例如從函數返回本地對象時的often)。現在std :: move的逆是否存在?

,我想知道(尤指在局部返回和隱含的舉動有情況下),如果有這樣的事情爲std::move反將防止移動對象(但仍允許複製)。

這是否有意義?

+2

我有一個問題,但:*你爲什麼需要這個*有可能甚至要返回本地對象,而且它可能只是通過(N)RVO創建 - 一個theoratical'返回標準? :: copy_only(v);'會阻止編譯器這樣做。 – Xeo

+0

刪除移動施工/分配。仍然不會阻止RVO。 – sehe

+2

'std :: unmove'。也可能是'std :: demove'。或者可能是'antimove'或'dontmove'?'movewithoutmoving'? 'movebackintime','moveelephanttoblockthepath'?沒有? –

回答

2

std::move左值轉換爲右值,並且它由基本上static_cast執行此。最接近我能想到的是相反的是這兩種類型轉換:

static_cast<T &>(/*rvalue-expression*/) 
static_cast<const T&>(/*rvalue-expression*/) 

這方面的例子可以在下面看到:

#include <iostream> 

void f(const int &) 
{ std::cout << "const-lval-ref" << std::endl; } 

void f(int &&) 
{ std::cout << "rval-ref" << std::endl; } 

int main() 
{ 
    f(static_cast<const int &>(3)); 
    return 0; 
} 

鑄造prvalue 3const int &確保左值選擇了f的過載。

在大多數情況下,你將自動得到這個右值到左值修改,只需賦值給一個變量:

int a = 3; 

當這條線後使用a,這將是一個左值。這是真實的,即使a聲明爲右值引用:

int &&a = 3; 

在這裏,a成爲一個左值(基本上是因爲它「有一個名字」)。

唯一的情況,我可以想象一個明確的演員陣營有任何相關的影響是我的第一個例子上面。並且在那裏,當處理諸如3之類的價格或者通過複製函數調用返回的臨時對象時,唯一合法的轉換是const引用(非const引用不允許綁定到prvalue)。

+0

將靜態轉換爲const引用'static_cast '是否真的阻止函數返回的隱式移動? –

+1

不,函數返回的類型最終由函數聲明中的返回類型決定。如果您在返回之前投射對象,它最終會再次投射到官方返回類型中。如果返回類型是非參考,您將得到一個prvalue;如果它是一個右值引用,你會得到一個xvalue。 (但這相當於'std :: move'的行爲:如果函數返回類型被定義爲左值引用,則在返回之前的'std :: move'將不會啓用移動語義。) – jogojapan

+0

因此,如果 - 無論出於什麼扭曲的原因 - 人們希望阻止返回的隱式動作,人們將不得不創建第二個局部變量來保存返回,然後返回該返回值,對嗎? ('T local1; ... T local2 = local1;/* < - copy */... return local2;/* < - may move * /' –

0

防止對象被移動的解決方案是使對象的移動構造函數爲私有,這樣對象不能被移動但可以被複制。

實施例與移動:

enter code here 

#include <iostream> 

class A { 
public: 
    std::string s; 
    A() : s("test") {} 
    A(const A& o) : s(o.s) { std::cout << "move failed!\n";} 
    A(A&& o) : s(std::move(o.s)) { std::cout << "move was succesfull!\n"; } 
}; 

int main(int argc, const char * argv[]) 
{ 
    A firsObject; 
    A secondObject = std::move(firsObject); 
    return 0; 
} 

與移動實施例禁用:

#include <iostream> 

class A { 
public: 
    std::string s; 
    A() : s("test") {} 
    A(const A& o) : s(o.s) { std::cout << "move failed!\n";} 

private: 
    A(A&& o) : s(std::move(o.s)) { std::cout << "move was succesfull!\n"; } 
}; 

int main(int argc, const char * argv[]) 
{ 
    A firsObject; 
    A secondObject = std::move(firsObject); 
    return 0; 
} 
+0

爲什麼有構造函數呢? –

+0

@R。馬丁霍費爾南德斯,你是對的,移動構造函數可以簡單地省略。在上面的例子中,當你需要它的時候,我想到了一種情況,這樣你可以聲明一個朋友類/方法,如果有必要的話,仍然可以使用移動構造函數。 –

0
template<class T> 
T& unmove(T&& t) 
{ 
    return t; 
} 

這將改變參數表達式的值類別爲一個左值,不管它是什麼。

void f(const int&); // copy version 
void f(int&&); // move version 

int main() 
{ 
    int i = ...; 

    f(42); // calls move version 
    f(move(i)); // calls move version 
    f(i); // calls copy version 

    f(unmove(42)); // calls copy version 
    f(unmove(move(i))); // calls copy version 
    f(unmove(i)); // calls copy version 
} 
+0

當然這不能解決在問題 –

+0

@MartinBa中特別強調的隱式移動迴歸情況:你的意思就像'return unmove(expr);'例如?它也會在那裏工作。 –

+0

是的,'return unmove(local_variable);' –

相關問題