Есть ли смысл перегружать set(/*args*/) перемещением ?:

//example:
class Person {
private:

    //properties
    std::string name;
    std::string address;
    std::string favmovie;

public:

    //set without operator=
    void set(const std::string& name, const std::string& address, const std::string& favmovie) {
        this->name = name;
        this->address = address;
        this->favmovie = favmovie;

        return;
    }

    //set without operator=
    void set(std::string&& name, std::string&& address, std::string&& favmovie) {
        this->name = std::move(name);
        this->address = std::move(address);
        this->favmovie = std::move(favmovie);

        return;
    }

    Person(const std::string& name, const std::string& address, const std::string& favmovie) 
    : name(name), address(address), favmovie(favmovie) {

    }

    Person(std::string&& name, std::string&& address, std::string&& favmovie) 
    : name(std::move(name)), address(std::move(address)), favmovie(std::move(favmovie)) {

    }

};

Это похоже на копирование и вставку с небольшим редактированием, но я делаю это для каждой функции или метода с соответствующими целями, которые у меня есть до сих пор, чтобы сделать их высокопроизводительными. Но это хорошая практика?

2
tistCoder 26 Ноя 2016 в 23:46

3 ответа

Лучший ответ

Ответ @ MM имеет тот недостаток, что хранилище будет перераспределяться каждый раз при вызове set, тогда как передача аргументов по ссылке позволит просто копировать данные без перераспределения, если их емкость уже достаточна для хранения данные, передаваемые через аргументы. Дополнительные сведения см. В выступлении Херба Саттера на CppCon. Так что я бы рекомендовал

void set(const std::string &name, const std::string &adress, const std::string &favmovie)
{
    this->name = name;
    this->adress = adress;
    this->favmovie = favmovie;
}

Конструкторы могут использовать умный трюк с передачей по значению, но если это действительно низкоуровневый код, который сильно проигрывает, оптимизация там, вероятно, не стоит того, ИМО.

2
sfjac 10 Дек 2016 в 23:24

Здесь вы используете передачу по значению:

void set(std::string name, std::string adress, std::string favmovie)
{
    this->name = std::move(name);
    this->adress = std::move(adress);
    this->favmovie = std::move(favmovie);
}

Затем, если аргумент является rvalue, он будет перемещен в параметр, чем затем перемещен в this - два хода, без копий. В то время как в эталонной версии const lvalue всегда есть копия. В случае аргумента lvalue есть 1 копия в обоих случаях (и 1 дополнительный ход в версии значения, но ходы дешевы и могут быть опущены в любом случае).

2
M.M 26 Ноя 2016 в 21:24

Если сама цель функции не выигрывает от семантики перемещения и функция не выигрывает от наличия ссылки на изменяемый параметр, нет причин иметь перегруженную версию, которая принимает ссылку rvalue в качестве параметра.

Очевидно, что для показанной здесь простой функции ответ отрицательный. Но было бы несложно придумать пример, в котором функция где-нибудь хранит свой параметр. В этом случае наличие перегруженной версии, которая использует семантику перемещения, вместо необходимости копировать-конструировать объект с целью его хранения, будет иметь очевидные преимущества.

Все сводится к тому, для чего функции нужен параметр.

0
Sam Varshavchik 26 Ноя 2016 в 20:52