c++ - c++11 中 std::move 操作的行为

标签 c++ 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 和右值引用的一个重大(且持续)的误解是 std::move 对对象(或按该顺序的某事)做了一些事情。

事实并非如此。 std::move 实际上只是将其参数转换为右值引用类型并返回它。基于调用采用右值引用的版本(而不是采用值或左值引用的版本)这一事实,对对象所做的任何事情都发生在移动构造函数、移动赋值运算符(等)中。

就你问的具体问题而言,至少根据你代码中的注释,你似乎有一些误解。 a2=std::move(a1); 上的评论说您正在执行“从 xvalue 移动赋值”。那是……充其量是误导。一个 xvalue 是一个将立即 eXpire 的值。它几乎是函数的返回值:

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

在这种情况下,bar() 是一个 xvalue,因为 bar 返回一个对过期对象的右值引用(超出范围) 作为函数完成执行。

就您提出的具体问题而言,我怀疑这主要归结为一个问题,即您的标准库是否(如果是,究竟如何)实现 std::string 的移动构造函数>。例如,当使用 g++ (4.9.1) 时,我得到与你相同的结果——b1.s 包含 test 在被用作源之前和之后一个 Action 。另一方面,如果我使用 MS VC++ 14 CTP,我会在移动前得到 b1.s="test",在移动后得到 b1.s=""。虽然我还没有测试过,但我希望 Clang 的结果是一样的。简而言之,看起来 gcc 的标准库并没有真正实现 std::stringmove 赋值/构造(但是——至少从 v 4.9 开始——我还没有看过 5.0)。

关于c++ - c++11 中 std::move 操作的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28058312/

相关文章:

c++ - 带有模板参数的自定义 C++ 异常

c++ - max_bucket_count 函数的意外行为

c++ - 从多个线程更新最大值

c++ - QueryPerformanceCounter函数在在线判断中的使用

c++ - 如何在 OpenGL (2.1) 中将纹理添加到顶点缓冲区对象

c++ - 何时在 C++ 中使用 __declspec(dllexport)

c++ - 如何解决 <<ClassName>> 的 "undefined reference to ` vtable 错误?

c++ - 我什么时候会在 constexpr 上使用 std::integral_constant?

c++ - gcc 中的 -O2 和 -fPIC 选项

c++ - SQLite C/C++ 接口(interface) : memory increasing while insert data into table