Перемещение членов класса, переданных как аргумент ссылки const - PullRequest
1 голос
/ 27 мая 2020

Учитывая:

template <typename... Args>
ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(std::move(inserter.key),
               std::move(inserter.fileName));
    } else {
        insert(std::move(inserter.key),
               std::move(inserter.fileName),
               std::move(std::get<Args...>(inserter.tuple)));
    }

    return *this;
}

Как вы думаете, это правильное использование семантики перемещения?

Экземпляр inserter ResourceInserter передается как константная ссылка.

Ответы [ 3 ]

2 голосов
/ 27 мая 2020

Нет.

Вы выполняете трансляцию на const Key && et c. Key::Key(const Key&&) обычно не может сделать ничего полезного, поэтому вы будете копировать.

Вы можете захотеть иметь пару перегрузок

template <typename... Args>
ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(inserter.key,
               inserter.fileName);
    } else {
        insert(inserter.key,
               inserter.fileName,
               std::get<Args...>(inserter.tuple));
    }

    return *this;
}

template <typename... Args>
ResourceHolder& operator+=(ResourceInserter<Key, Args...>&& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(std::move(inserter.key),
               std::move(inserter.fileName));
    } else {
        insert(std::move(inserter.key),
               std::move(inserter.fileName),
               std::move(std::get<Args...>(inserter.tuple)));
    }

    return *this;
}

Куда вы переезжаете от членов rvalue inserter

2 голосов
/ 27 мая 2020

Вопреки названию, std :: move на самом деле ничего не перемещает. Он просто сообщает компилятору, что нужно попытаться переместить (т.е. указать, что объект t может быть «перемещен из» путем преобразования его в ссылочный тип rvalue [более конкретно, путем создания xvalue выражение ]).

Однако в вашем классе нет конструктора, который принимает const inserter&&, вместо этого он будет использовать конструктор вашего класса (неявный или явный) и безопасно копировать. Ни опасности, ни ловушки. Если конструктор копирования по какой-либо причине отключен, вы получите ошибку компиляции.

Попробуйте следующее:

#include <iostream>
struct Test {
   Test() { }
   Test(const Test& ) { std::cout << "COPY" << std::endl; }
   Test(Test&&)       { std::cout << "MOVE" << std::endl; }
};

int main() 
{
    const Test t;
    Test t2 = std::move(t);
    return 0;
}

печатает COPY, а не MOVE.

2 голосов
/ 27 мая 2020

Перемещение константных объектов обычно является простой копией (если вы не перегружаете Object(const Object&&)), поэтому использование std::move кажется бесполезным.

Если члены ResourceInserter являются (неконстантными) ссылками, ваш const ResourceInserter& вводит в заблуждение, и ваш ход действительно произойдет.

...