运算符+和移动语义 [英] operator+ and move semantics
问题描述
如何用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 ofoperator+=
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屋!