Почему конструктор перемещения / оператор присваивания в 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++ не реализует фактический стандарт, но более раннюю версию.