2017-04-03 32 views
2

可能是一個蹩腳的問題,但我一直未能找到全面的答案。將它們用作emplace_back的參數後使用變量是否正確?

std::vector::emplace_back的參數是r值參考。據我所知,在通過r值引用傳入某個地方後使用object是不安全的。我的意思是:

std::string str("hello world"); 
std::string str2(std::move(str)); // string::string(string &&); 
cout << str;      // unsafe, str was moved to str2 

那麼,下面的例子會發生什麼?

std::vector<std::string> array; 
std::string str("hello world"); // what if add 'const' qualifier here? 
array.emplace_back(str);   // template <class... Args> 
            // void emplace_back (Args&&... args); 
std::cout << str;     // safe or not? str was moved or copied? 

我真的很困惑。我的測試表明,stremplace_back之後可以安全使用,但是我的(壞的?)邏輯告訴我str已被移動,之後不應使用。

PS。對不起我的英文:)

+1

我想說明的是,'emplace_back'是一個'委託構造函數',所以你不需要發送它的類型,你可以發送任何參數給對象構造函數,矢量'例如你可以'emplace_back(7,'c')'。如果你已經有了這個類型的變量,'push_back()'更具慣用性。 – sp2danny

+0

請參閱http://stackoverflow.com/questions/4303513/push-back-vs-emplace-back – sp2danny

回答

9

emplace -style函數的參數是轉發引用,這意味着它們成爲左值參數和左值參數的左值引用。

隨着

array.emplace_back(str); 

str是一個左值(你有沒有它std::move強制轉換爲右值),所以它會被複制。通話結束後它將保持其價值。

+0

另外,在第一個示例中使用'str'也應該是「安全的」。 – juanchopanza

+0

只有當你不關心它的價值 – Brian

+1

移動的物體是唯一安全的破壞,除非他們的文檔另有說明。 'std :: string'的文檔說'未指定但是有效' – sp2danny

1

emplace_back將複製l值並移動r值。

有人可能會用一個簡單的例子測試:

struct test { 
    test() { 
     std::cout << "Default-constructed\n"; 
    } 

    test(test const&) { 
     std::cout << "Copy-constructed\n"; 
    } 

    test(test &&) { 
     std::cout << "Move-constructed\n"; 
    } 

    ~test() { 
     std::cout << "Destructed\n"; 
    } 

    test& operator=(test const&) { 
     std::cout << "Copy-assigned\n"; 
     return *this; 
    } 

    test& operator=(test &&) { 
     std::cout << "Move-assigned\n"; 
     return *this; 
    } 
}; 

int main() { 
    std::vector<test> vector; 
    test t; 
    vector.emplace_back(t);//The important one 
    vector.emplace_back(test{}); 
    return 0; 
} 

這個(應該,假設複製ellision在這裏不適用),導致下面的輸出:

Default-constructed 
Copy-constructed //The important one 
Move-constructed 
Destructed 
Destructed 
Destructed 

注意,當emplace_back被調用了一個l值,複製構造函數被調用。所以在你的情況下,字符串將被複制,而不是移動,因此安全地繼續在矢量之外使用。

還值得注意的是,Move-Semantics通常要求移動的對象是「處於未指定但是有效的狀態」,這意味着它實際上不應該是「不安全的」以使用移動的對象。儘管它仍然有奇怪的效果,並且可以根據該對象的有效狀態可以包含的內容調用未定義的行爲(例如,如果您試圖取消引用已移動的unique_ptr或其他類似對象)。

+0

僅移動語義_require_該對象可被銷燬。 **標準庫類型**通常會提供更多保證。 – sp2danny

1

標準庫對象通常處於「有效但未指定狀態」。

有效但非指定狀態
,並非只是對象的不變量得到滿足,並作爲其類型指定在 對象的行爲操作 [實施例中指定的對象的值:如果std::vector<int>類型的對象x處於有效但未指定狀態,x.empty()可以是無條件呼叫 ,只有在x.empty()返回false時才能呼叫x.front()末端示例]

通常這意味着要麼空的,或保持原始值。移動一個int可能不會重置其值。

某些類型更具體,例如unique_ptr從中移除後總是保留nullptr。

所以,在這種情況下

std::string str("hello world"); 
std::string str2(std::move(str)); // string::string(string &&); 
cout << str; 

的代碼是有效的,但我們不知道的輸出將是什麼,如果有的話。使其不夠用。

這個想法是,你應該讓這個變量在被移出之後超出範圍,或者給它分配一個新值以進一步使用它。

+0

這是有用的信息,但實際上並沒有回答這個問題,因爲'emplace_back()'不會從左值移動。 – sp2danny

+0

好吧,我可能只回答了問題的第一部分,其中*是*移動,而不是專門關於'emplace_back'。 –

相關問題