Я немного изменил вашу main
процедуру, чтобы лучше понять вывод:
int main()
{
std::cout << "default\n";
Map m;
std::cout << "\ncopy\n";
Map m1(m);
std::cout << "\nmove\n";
Map m2(Map(m1));
std::cout << "\nmove\n";
Map m3(createMap());
}
А вот вывод с g++ -fno-elide-constructors
:
default
Map()
copy
Map(const Map& pattern)
move
move
Map()
Map(Map&& tmp)
Map(Map&& tmp)
Как уже отмечали другие, Map m2(Map(m1));
действительно является объявлением функции, поэтому вы не получите никакого вывода. Второй ход - , а не , интерпретируемый как объявление функции, потому что createMap
не является именем типа. Здесь задействованы два конструктора перемещения. Один перемещает временный объект, созданный путем оценки Map()
, во временный объект, созданный путем оценки createMap()
, а второй шаг инициализирует m3
из последнего. Это именно то, что и следовало ожидать.
Если вы исправите первый ход, написав Map m2((Map(m1)));
, вы получите:
move
Map(const Map& pattern)
Map(Map&& tmp)
Опять без сюрпризов. Конструктор копирования вызывается путем оценки Map(m1)
, и этот временный объект затем перемещается в m2
. Если вы компилируете без -fno-elide-constructors
, операции перемещения исчезают, потому что они заменяются еще более эффективными оптимизациями, такими как RVO или NRVO:
default
Map()
copy
Map(const Map& pattern)
move
Map(const Map& pattern)
move
Map()
Я уверен, что в Visual C ++ есть опция компилятора, похожая на -fno-elide-constructors
, с которой вы можете поиграть, чтобы лучше понять семантику перемещения.