8
#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;
}

我的预期输出应该是:

A()
A(A&&)
~A()
~A()

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

A()
~A()
~A()

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

4

3 回答 3

14

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

于 2012-09-28T21:30:24.603 回答
7

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

具体而言,在您的示例中,这以两种方式表现出来:

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

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

于 2012-09-28T21:33:21.983 回答
1

我不认为移动构造函数的声明会阻止复制ctor的生成。...而且编译器似乎更喜欢复制构造函数而不是移动构造函数。

实际上,根据 12.8 [class.copy] 第 7 段,移动构造函数的存在应该阻止复制构造函数:

如果类定义没有显式声明复制构造函数,则隐式声明。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值(8.4)。

然而,移动构造的细节直到过程后期才改变,似乎 VC++ 没有实现实际标准,而是较早的修订版。

于 2012-09-28T21:23:35.383 回答