为什么C++ 11的移动构造函数/赋值运算符不按预期运行

xml*_*lmx 8 c++ visual-c++ move-semantics c++11 visual-studio-2012

#include <iostream>

using namespace std;

struct A
{
    A()
    {
        cout << "A()" << endl;
    }

    ~A()
    {
        cout << "~A()" << endl;
    }

    A(A&&)
    {
        cout << "A(A&&)" << endl;
    }

    A& operator =(A&&)
    {
        cout << "A& operator =(A&&)" << endl;
        return *this;
    }
};

struct B
{
    // According to the C++11, the move ctor/assignment operator
    // should be implicitly declared and defined. The move ctor
    // /assignment operator should implicitly call class A's move
    // ctor/assignment operator to move member a.
    A a;
};

B f()
{
    B b;

    // The compiler knows b is a temporary object, so implicitly 
    // defined move ctor/assignment operator of class B should be
    // called here. Which will cause A's move ctor is called.
    return b; 
}

int main()
{
    f();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的预期输出应该是:

A()
A(A&&)
~A()
~A()
Run Code Online (Sandbox Code Playgroud)

但是,实际输出是:( C++编译器是:Visual Studio 2012)

A()
~A()
~A()
Run Code Online (Sandbox Code Playgroud)

这是VC++的错误吗?还是只是我的误会?

ild*_*arn 14

根据这篇博文,VC++ 2012目前实现的是N2844 + DR1138,而不是N3053.因此,编译器不会为您隐式生成移动构造函数或赋值运算符.如果你添加显式默认值和移动构造函数,B那么你将得到你期望的输出.

  • 很难过听到这个.我认为这是C++ 11的一个非常基本的特性. (5认同)

Jam*_*lis 7

Visual C++ 2012没有为rvalue引用和移动操作实现最终的C++ 11规范(规范在标准化过程中多次更改).您可以在rvalue引用下的Visual C++团队博客文章"Visual C++ 11中的C++ 11功能"中找到更多信息.

在您的示例中,具体来说,这表现在两个方面:

  • 用户定义的移动操作的定义A不会抑制隐式声明的复制操作.

  • 没有隐式定义的移动操作B.