运算符+和移动语义 [英] operator+ and move semantics

查看:89
本文介绍了运算符+和移动语义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何用operator+实现移动语义的正确方法?类似于std::string的工作原理?

How is the proper way to implement move semantics with operator+? Similarly to how it works for std::string?

我尝试了以下方法,但是我希望有一些更优雅,可能更正确的方法:

I have attempted the following, however I was hoping there was some more elegant and possibly more correct way to do it:

class path
{
    std::vector<std::string> path_;
public:

    path& path::operator+=(const path& other)
    {
        path_.insert(std::begin(path_), std::begin(other.path_), std::end(other.path_));
        return *this;
    }

    path& path::operator+=(path&& other)
    {
        path_.insert(std::begin(path_), std::make_move_iterator(std::begin(other.path_)), std::make_move_iterator(std::end(other.path_)));
        return *this;
    }
};

template<typename L, typename R>
typename std::enable_if<std::is_convertible<path, L>::value, path>::type operator+(const L& lhs, const R& rhs)
{
    auto tmp = std::forward<L>(lhs);
    tmp     += std::forward<R>(rhs);
    return tmp;
}

推荐答案

方法太复杂了. :)只要遵守您应该遵循的规则即可:

Way too complicated. :) Just abide by the rule you already should've followed:

  • 按值获取operator+的lhs
  • 根据lhs上的operator+=实施operator+
  • Take the lhs of operator+ by value
  • implement operator+ in terms of operator+= on the lhs

由于复制省略和RVO,这在C ++ 03中已经成立.经验法则:如果仍要进行复制,请在参数中进行复制.

This was already true in C++03, because of copy elision and RVO. The rule of thumb: If you make a copy anyways, make it in the parameters.

请牢记:

#include <iterator>
#include <utility>

class path
{
    std::vector<std::string> path_;
public:

    path& operator+=(path other)
    {
        auto op_begin = std::make_move_iterator(std::begin(other.path_));
        auto op_end = std::make_move_iterator(std::end(other.path_));
        path_.reserve(path_.size() + other.path_.size());
        path_.insert(std::end(path_), op_begin, op_end);
        return *this;
    }
};

path operator+(path lhs, path rhs)
{
  return std::move(lhs += std::move(rhs));
}

这应该是最理想的形式.请注意,我也将您的operator+=更改为实际上追加的路径,而不是添加路径(我希望这就是您所想的.否则,请再次将其更改为std::begin(path_)).

This should be the most optimal form. Note that I also changed your operator+= to actually append the path, and not prepend (I hope that's what you had in mind. If not, feel free to change it to std::begin(path_) again).

我还制作了operator+operator+=值的rhs,然后将它们四处移动. std::make_move_iterator也是一个不错的实用程序.顾名思义,它不会复制,而是移动所指向的元素.实际上,这应该会很快.

I also made the rhs of operator+ and operator+= values and then just moved them around. std::make_move_iterator is also a nice utility. As the name implies, instead of copying, it moves the pointed-at elements. This should really be as fast as it's going to get.

另一个版本可能是在operator+=中使用std::move的迭代器版本:

Another version might be to use the iterator version of std::move in operator+=:

path& operator+=(path other)
{
    path_.reserve(path_.size() + other.path_.size());
    std::move(other.begin(), other.end(), std::back_inserter(path_));
    return *this;
}

这篇关于运算符+和移动语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆