Почему конструктор перемещения / оператор присваивания в C++11 не работает должным образом?

#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++? или только мое недоразумение?

3 ответа

Решение

Согласно этому сообщению в блоге, VC++ 2012 в настоящее время реализует N2844 + DR1138, но не N3053. В результате компилятор не генерирует неявно конструкторы перемещения или операторы присваивания для вас. Если вы добавите явное значение по умолчанию и переместите конструкторы в B тогда вы получите ожидаемый результат.

Visual C++ 2012 не реализует окончательную спецификацию C++11 для rvalue ссылок и операций перемещения (спецификация менялась несколько раз в процессе стандартизации). Вы можете найти больше информации в посте блога Visual C++ Team, "Возможности C++11 в Visual C++11", под ссылками rvalue.

В вашем примере это проявляется двумя способами:

  • определение пользовательских операций перемещения в A не подавляйте неявно объявленные операции копирования.

  • не существует неявно определенных операций перемещения для B,

Я не думаю, что генерация копии ctor предотвращается объявлением конструктора перемещения.... и кажется, что компилятор предпочитает конструктор копирования, а не конструктор перемещения.

На самом деле, согласно пункту 7 12.8 [class.copy], наличие конструктора перемещения должно препятствовать конструктору копирования:

Если определение класса не объявляет явно конструктор копирования, он объявляется неявно. Если определение класса объявляет конструктор перемещения или оператор присваивания перемещения, неявно объявленный конструктор копирования определяется как удаленный; в противном случае он определяется как дефолтный (8.4).

Тем не менее, детали построения перемещения были изменены до поздней стадии процесса, и кажется, что VC++ не реализует фактический стандарт, но более раннюю версию.

Другие вопросы по тегам