繁体   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