簡體   English   中英

在c ++ 11中std :: move操作的行為

[英]Behaviour of std::move operation in c++11

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

struct A {
    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)) {}
    A& operator=(const A&) { std::cout << "copy assigned\n"; return *this; }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << "move assigned\n";`enter code here`
        return *this;
    }
};

A f(A a) { return a; }

struct B : A {
    std::string s2;
    int n;
    // implicit move assignment operator B& B::operator=(B&&)
    // calls A's move assignment operator
    // calls s2's move assignment operator
    // and makes a bitwise copy of n
};

struct C : B {
    ~C() {}; // destructor prevents implicit move assignment
};

struct D : B {
    D() {}
    ~D() {}; // destructor would prevent implicit move assignment
    //D& operator=(D&&) = default; // force a move assignment anyway 
};

int main()
{
    A a1, a2;
    std::cout << "Trying to move-assign A from rvalue temporary\n";
    a1 = f(A()); // move-assignment from rvalue temporary
    std::cout << "Trying to move-assign A from xvalue\n";
    a2 = std::move(a1); // move-assignment from xvalue

    std::cout << "Trying to move-assign B\n";
    B b1, b2;
    std::cout << "Before move, b1.s = \"" << b1.s << "\"\n";
    b2 = std::move(b1); // calls implicit move assignment
    std::cout << "After move, b1.s = \"" << b1.s << "\"\n";

    std::cout << "Trying to move-assign C\n";
    C c1, c2;
    c2 = std::move(c1); // calls the copy assignment operator

    std::cout << "Trying to move-assign D\n";
    D d1, d2;
//  d2 = std::move(d1);
}

執行a2 = std::move(a1)語句時,行為與執行語句b2 = std::move(b1) 在下面的語句中,移動操作后b1.s不會變空,而a1.s在移動操作后變空。

誰能告訴那里究竟發生了什么?

關於C ++ 11和rvalue引用的一個很好的(和常量的)誤解是std::move對一個對象(或者那個順序上的東西)做了一些事情。

它沒有。 std::move實際上只是將其參數轉換為rvalue引用類型並返回該參數。 對對象所做的任何事情都發生在移動構造函數中,移動賦值運算符(等等)基於調用采用右值引用的版本的事實(而不是采用值或左值引用的版本)。

至於您提出的具體問題,至少根據您的代碼中的注釋,您似乎有一些誤解。 關於a2=std::move(a1); 說你正在做“從xvalue移動任務”。 那......充其量只是誤導。 xvalue是一個立即進行eXpire的值。 這幾乎是函數的返回值:

Foo &&bar() { 
    Foo f;
    // ...
    return f;
}

在這種情況下, bar()是一個xvalue因為當函數完成執行時, bar返回對一個到期(超出范圍)的對象的rvalue引用。

至於你提出的具體問題,我懷疑它主要歸結為一個問題,即你的標准庫是否(以及如果確實如此)實現了std::string的移動構造函數。 例如,當使用g ++(4.9.1)時,我得到了相同的結果 - b1.s包含在用作移動源之前和之后的test 另一方面,如果我使用MS VC ++ 14 CTP,我會在移動前得到b1.s="test" ,移動后得到b1.s="" 雖然我沒有測試過,但我希望Clang的結果是一樣的。 簡而言之,看起來gcc的標准庫並沒有真正實現std::string move賦值/構造(至少從v 4.9開始 - 我還沒有看過5.0)。

通常移動賦值是作為std::string的交換實現的,那么為什么字符串變為空,因為它總是用"test"初始化?

在哪里看到a1.s因為沒有打印而變空?

在這里看不到任何奇怪的行為。 兩者都以同樣的方式對待。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM