Почему этот конструктор перемещения такой жадный?

У меня есть следующий код:

#include <iostream>

class foo_class {
    std::string value;
public:
    foo_class(const foo_class& v) : value{v.value} {
        std::cout << "copy constructor" << std::endl;
    }

    foo_class(foo_class&& v) : value{std::move(v.value)} {
        std::cout << "move constructor" << std::endl;
    }

    ~foo_class() {
        std::cout << "destructor" << std::endl;
    }

    foo_class(std::string v) : value{std::move(v)} {
        std::cout << "type constructor" << std::endl;
    }
};

struct Data {
    foo_class a;
    foo_class b;
};

int main() {
    std::string c = "3";
    Data x{c,c+"3"};
    return 0;
}

ВАЖНО, я компилирую его с помощью GCC и Clang (4.8.2 и 3.4 соответственно) и флага -fno-elide-constructors, поэтому мы не пропускаем копию/ перемещать конструкторы.

Результат выполнения следующий:

type constructor
move constructor
destructor
type constructor
move constructor
destructor
destructor
destructor

Это означает, что конструктор копирования вообще не используется, даже если его следует использовать для первого аргумента конструктора структуры Data.

Далее, если я удалю конструктор копирования, код по-прежнему будет законным в соответствии с моими компиляторами, но, по моему мнению, должен быть незаконным, потому что я не выполняю приведение к && (используя std::move) при передаче первого аргумента конструктора данных.

У меня простой вопрос: Почему это происходит? Я что-то упустил?


person José Manuel    schedule 16.08.2014    source источник
comment
Почему вы считаете, что это должна быть копия? Оба аргумента проходят преобразование, поэтому у вас есть два временных аргумента, которые можно перемещать.   -  person Cat Plus Plus    schedule 16.08.2014
comment
Означает ли это, что я не мог добиться идеальной переадресации значения std::string без объявления конструктора пересылки в Data?   -  person José Manuel    schedule 16.08.2014
comment
Perfect Forwarding — это концепция, которая применяется к шаблонным функциям, которых у вас нет. Ваш код перемещает содержимое строк непосредственно в x, хотя это то же самое, что и набор идеальных функций пересылки. Хотя у вас есть одна дополнительная копия в конструкторе типов.   -  person Mooing Duck    schedule 15.03.2018


Ответы (1)


Поскольку объекты foo_class, созданные в

Data x{c,c+"3"};

оба временные. Поэтому они вызывают конструктор move вместо конструктора copy.

type constructor // 1. Construct a temporary foo_class object out of string "c" for a
move constructor // 2. Move the temporary object created above to x.a
destructor       // 3. Destruct the temporary foo_class object created in 1
type constructor // 4. Same as 1, but the object is for b, and the string "33"
move constructor // 5. Same as 2, moved to x.b
destructor       // 6. Destruct the temporary foo_class object created in 4
destructor       // 7. Destruct x.b
destructor       // 8. Destruct x.a
person WiSaGaN    schedule 16.08.2014