STL map::insert 应该支持 move_iterators 的移动语义吗?

Should STL map::insert support move semantics with move_iterators?

我有大量数据要从文件加载到 map 中,该文件已经按排序顺序排列(因为它是从地图序列化的)。 我发现首先将数据加载到 vector,然后使用 insert 批量加载到 map 会更快。这在 19 秒的加载时间中节省了一秒多一点。

value_type是一个包含其他结构向量的结构。加载完成后我不需要 vector,所以我在调用 map::insert 时使用了 move_iterator。使用 MSVC 2015 (VC14),数据不会移动到地图中,而是通过 const_reference 深入到 STL 代码中进行复制。

这是一个符合标准的实现,忽略数据的移动吗?

template<typename Stream, typename Key, typename Type, typename Traits, typename Allocator>
bool const read(Stream &is, std::map<Key, Type, Traits, Allocator> &map)
{
    size_t size;
    read(is, size);

    std::vector<std::pair<Key, Type>> items(size);
    for (size_t i=0; i<size; ++i)
    {
        auto &item = items[i];
        if (!read(is, item.first)  ||  !read(is, item.second))
            return false;
    }
    map.insert(std::make_move_iterator(items.begin()), std::make_move_iterator(items.end()));

    return !!is;
}

我已经解决了将 map.insert 替换为

的问题
for (auto &item : items)
    map.insert(std::move(item));

虽然不是很整洁,但确实又节省了 0.6 秒。

Is this a standard-compliant implementation, to ignore the moving of data?

标准说 insert() 函数:

Requires: value_type shall be EmplaceConstructible into X from *i.

因此必须可以从迭代器的 reference 类型构造 value_type ,在本例中是右值引用。这意味着您可以使用仅移动(即不可复制)键类型和映射类型,只要迭代器 returns 右值可以转换为映射的 value_type 它就必须工作。

应该使用构造函数 std::pair<const Key, Type>::pair<K2, T2>(pair<K2, T2>&&) 将来自迭代器的右值构造到映射中的值。

这对我适用于 GCC,以及使用在线编译器的最新 VC++:

#include <vector>
#include <map>
#include <iterator>

struct MoveOnly {
  MoveOnly() = default;
  MoveOnly(MoveOnly&&) = default;
};

bool operator<(const MoveOnly&, const MoveOnly&) { return false; }

template<typename Key, typename Type, typename Traits, typename Allocator>
void read(std::map<Key, Type, Traits, Allocator> &map)
{
    std::vector<std::pair<Key, Type>> items(1);
    map.insert(std::make_move_iterator(items.begin()), std::make_move_iterator(items.end()));
}

int main()
{
  std::map<MoveOnly, MoveOnly> m;
  read(m);
}

如果您指定了自己的移动构造函数或移动赋值运算符,则应将其标记为'noexcept'。否则标准容器将复制元素。 在此处查看文档:http://en.cppreference.com/w/cpp/language/noexcept_spec