2012-11-29 99 views
10

該程序試圖移動串出的函數,並且將其用於另一個字符串的結構:是否有可能將std ::將對象移出函數? (C++ 11)

#include <iostream> 
#include <string> 
#include <utility> 

std::string && Get_String(void); 

int main(){ 

    std::string str{Get_String()}; 
    std::cout << str << std::endl; 

    return 0; 
} 

std::string && Get_String(void){ 

    std::string str{"hello world"}; 

    return std::move(str); 
} 

程序編譯,但在執行時段錯誤。


這是我的理由:Get_String將創建一個本地字符串。該字符串的副本需要在字符串超出範圍之前進行並返回。該副本將用於在main中構造字符串。但是,如果我將該字符串移出該函數,則不需要進行復制。

爲了理解移動語義,有人可以解釋爲什麼我在做什麼,可能沒有意義。是否可以將對象移出某個函數?


編輯:
它編譯並運行正常,如果我更改從函數簽名:

std::string && Get_String(void); 

std::string Get_String(void); 

是不是更有效地移動串在這種情況下返回?

+1

RVO解決了這個問題。不要使用'std :: move'來禁用它。 – chris

+0

@chris我應該返回值,編譯器會優化到我在做什麼呢? –

+0

是的,任何現代編譯器都應該刪除該副本。 – chris

回答

16

鑑於此例中,

X foo() 
{ 
    X x;  
    return x; 
} 

以下行爲有保證:

•如果X具有可訪問的複製或移動構造函數,編譯器可以 選擇的的Elid副本。這是所謂的(命名的)返回值 最優化((N)RVO),它甚至在C++ 11之前被指定,並且是大多數編譯器支持的 。
•否則,如果X有移動構造函數,則移動x
•否則,如果X有複製構造函數,則複製x
•否則,會發出編譯時錯誤。

還應注意,返回一個rvalue參考是一個錯誤,如果返回的對象是局部非靜態對象:

X&& foo() 
{ 
    X x; 
    return x; // ERROR: returns reference to nonexistent object 
} 

右邊的值可以參照作爲基準,並將其返回參照本地對象裝置你 返回一個不再存在的對象的引用。是否使用std::move()不是 的問題。

std::move()並不真正移動物體;它只將左值變成右值。

2

Get_String函數將右值引用綁定到函數本地對象。Rvalue引用對於即將被銷燬的事物是有用的,但對於已經被銷燬的事物的Lvalue引用也是一樣糟糕。

要移動本地對象出一個功能,您只需按類類型返回:

std::string Get_String(void) { 
    std::string str{"hello world"}; 
    return str; 
} 

如果編譯器不設法消除複製/移動完全,則返回值呼叫者得到將使用移動構造函數來構造,而不是拷貝構造,只要返回表達式爲:

  • 一個臨時的,或者
  • 單個標識符命名具有自動存儲持續時間的東西(如str以上),或
  • std::move(something)

(所以,你仍然可以有return std::move(str);是明確的,但在這裏是沒有必要的。)

相關問題