我应该总是为函数和方法实现移动语义吗?

时间:2016-11-26 20:46:20

标签: c++ performance move-semantics

使用move?:

重载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)) {

    }

};

感觉就像通过一点点编辑进行复制和粘贴,但我正在为每个功能或方法执行此操作,目前为止我已达到一致的目的,使它们具有高性能。但这是一个好习惯吗?

3 个答案:

答案 0 :(得分:2)

这是您使用pass-by-value的地方:

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左值参考版本,总会有一个副本。对于左值参数的情况,在两种情况下都有1个副本(在值版本中有1个额外的移动,但移动很便宜,无论如何都可以省略。)

答案 1 :(得分:2)

@ M.M的答案的缺点是每次调用set时都会重新分配存储空间,而通过引用传递参数将允许简单地复制数据,而无需重新分配容量已足以保存通过参数传入的数据。有关详细信息,请参阅Herb Sutter's CppCon talk。所以我建议

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

构造函数可以使用聪明的按值传递技巧,但除非它真的是低级代码,否则很可能不会有优势,IMO可能不值得。

答案 2 :(得分:0)

如果函数的目的本身不能从移动语义中受益,并且该函数不会受益于对可变参数的引用,则没有理由让一个重载版本将rvalue引用作为参数。

对于这里显示的简单功能,答案显然是否定的。但是想到一个函数将某个地方存储其参数的例子并不难。在这种情况下,拥有一个利用移动语义的重载版本,而不是为了存储它而复制构造对象,将会有明显的好处。

这一切都归结为函数需要其参数。