Не удается запустить конструктор перемещения

С++ 11

У меня проблемы с использованием конструктора перемещения. У меня есть простой класс-контейнер с именем Number, единственным элементом данных которого является целое число. У меня есть следующий код:

//Number.h
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>

class Number
{
public:
    Number();
    Number(int ipar);
    Number(const Number& src);
    Number(Number&& src);
private:
    int num;
};

#endif

и

//Number.cpp
#include "Number.h"

Number::Number()
{
    std::cout << "default ctor" << std::endl;
}

Number::Number(int ipar) : num(ipar)
{
    std::cout << "integer argument ctor" << std::endl;
}

Number::Number(const Number& src) : num(src.num)
{
    std::cout << "copy ctor" << std::endl;
}

Number::Number(Number&& src) : num(src.num)
{
    std::cout << "move ctor" << std::endl;
}

и

//main.cpp
#include "Number.h"
using namespace std;

int main()
{
    cout << "Part A:" << endl;
    Number n1(1);
    cout << "Part B:" << endl;
    Number n2(n1);
    cout << "Part C:" << endl;
    Number n3{Number{n1}};
    cout << "Part D:" << endl;
    Number n4(Number(n1));
    return 0;
}

Вывод:

Part A:
integer argument ctor
Part B:
copy ctor
Part C:
copy ctor
Part D:

Обратите внимание, что для части D нет выходных данных. Я ожидал, что выходные данные для частей A и B будут такими, какие я ожидал, а для других — нет.

Я ожидал этого для частей C и D:

Part C:
copy ctor
move ctor
Part D:
copy ctor
move ctor

Ожидание части C:

Я ожидал, что Number{n1} часть Number n3{Number{n1}} создаст временный безымянный объект Number, потому что между Number и открывающей фигурной скобкой нет имени, вызвав конструктор копирования с n1. Затем я ожидал, что Number n3 будет создан путем вызова конструктора перемещения с временным объектом.

Ожидание части D:

Поскольку это похоже на часть C, за исключением того, что вместо фигурных скобок используются круглые скобки, я ожидал, что эта часть будет вести себя и выводиться так же, как я ожидал от части C.

Вопрос:

Почему фактический результат отличается от моих ожиданий и как правильно получить желаемый результат?

Примечание. Если вы хотите скомпилировать это в Visual Studio, вам потребуется Компилятор Visual C++, ноябрь 2012 г., CTP или более поздняя версия для Visual Studio 2012, чтобы поддерживать единый синтаксис инициализации.


person CodeBricks    schedule 01.03.2013    source источник
comment
поиск исключения копирования и самый неприятный разбор   -  person sellibitze    schedule 01.03.2013


Ответы (1)


n4 является объявлением функции. n3 вызвано упущением копирования.

Убедитесь, что здесь я включил -fno-elide-constructors, чтобы избежать исключения копирования. Затем n3 показывает последовательность конструкторов копирования и перемещения.

Есть закомментированная строка, которая пытается использовать n4 в качестве объекта. Если вы раскомментируете его, вы увидите ошибку компилятора, сообщающую, что это функция.

Для того, чтобы n4 не интерпретировалось как объявление функции, вы можете поместить дополнительные круглые скобки вокруг временного параметра, чтобы предотвратить его просмотр в качестве параметра функции: Number n4((Number(n1))). С этим и -fno-elide-constructors происходит все, что вы ожидали.

Обратите внимание, что -fno-elide-constructors отсутствует в качестве опции в MSVC.

person pepper_chico    schedule 01.03.2013
comment
Вы также можете предотвратить объявление функции, написав Number n4(n1) или Number n4(Number(2)). Если вы действительно хотите, чтобы вызывался конструктор перемещения, напишите что-нибудь вроде Number n(std::move(Number(2)). Передача R-значения также вызовет конструктор перемещения. Попробовав это, я впервые узнал об оптимизации возвращаемого значения. - person Átila Neves; 01.03.2013
comment
+1, однако, пожалуйста, замените оптимизацию возвращаемого значения копированием. RVO — это всего лишь один из видов копирования. Но РВО здесь не применяется, потому что возврата нет. ;) - person sellibitze; 01.03.2013