1

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

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

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;
}
4

1 回答 1

2

太复杂了。:) 只需遵守您已经应该遵循的规则:

  • operator+按值取 lhs
  • operator+operator+=lhs 上实施

由于复制省略和 RVO,这在 C++03 中已经是正确的。经验法则:如果您仍然制作副本,请在参数中制作。

考虑到这一点:

#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_)再次更改)。

我还制作了 rhsoperator+operator+=值,然后只是移动它们。std::make_move_iterator也是一个不错的实用程序。顾名思义,它不是复制,而是移动指向的元素。这真的应该尽可能快。

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

path& operator+=(path other)
{
    path_.reserve(path_.size() + other.path_.size());
    std::move(other.begin(), other.end(), std::back_inserter(path_));
    return *this;
}
于 2011-12-31T11:11:00.320 回答