【问题标题】:Can I move-assign a std::map's contents into another std::map?我可以将 std::map 的内容移动分配到另一个 std::map 吗?
【发布时间】:2014-03-10 14:20:14
【问题描述】:

是否可以通过使用移动语义将临时 std::map temp 的内容插入到另一个 std::map m 中,这样临时的值不会被复制并被重用?

假设有:

std::map<int, Data> temp;
std::map<int, Data> m;

将值从temp 复制到m 的一种方法是:

m.insert(temp.begin(),temp.end());

如何将temp 元素移动m,而不是复制?

【问题讨论】:

    标签: c++ c++11 move-semantics


    【解决方案1】:

    提示: 先阅读更新!

    当前的 C++11 标准和 C++14 草案没有提供成员函数来启用此功能。正如 lavr 建议的那样,您仍然可以编写

    m.insert(make_move_iterator(begin(temp)),
             make_move_iterator(end  (temp)));
    

    这会将 从源容器移动到目标容器。但是,容器节点和键都不会被移动。这需要内存分配(至少用于在目标映射中创建新节点)。源容器中的元素数量将保持不变。复制背后的原因很简单:std::map 的值类型是std::pair&lt;const Key,T&gt;。从const Key 移动基本上是在复制密钥(除非有人重载了Key 构造函数,它采用const Key &amp;&amp;,对此我想不出足够的理由)。

    如果您需要将数据从一个容器移动到另一个容器,您可以考虑使用std::list 而不是std::map。它有一个member function splice,它可以在恒定时间内将元素从一个列表移动到另一个列表。

    更新:

    从 C++17 开始,函数 std::map::merge() 基本上将一个 std::map 的所有元素放入另一个 std::map 中,而不移动或复制实际元素,但仅通过重新指向内部指针。它与自 C++98 以来存在的std::list::splice() 非常相似。

    所以你可以写

    m.merge( temp );
    

    实现你的目标。这比将所有元素从一个容器复制或移动到另一个容器更有效。

    但要小心!冲突的键不会被解决:对于重合的键,什么都不会做。

    【讨论】:

    • 虽然const Key 将在移动对时被复制,而temp 将保持相同数量的元素,T 仍将被移动......所以如果T 是像std::vector 这样具有移动语义的大型结构,这仍然有意义,对吧?
    【解决方案2】:

    没有尝试过,但我认为std::move_iterator 在这里应该有所帮助:

     using it = std::map<int, Data>::iterator;
     using mv = std::move_iterator <it>;
    
     m.insert(mv(temp.begin()),mv(temp.end()));
    

    【讨论】:

    • 我很确定这不会因为上述原因而工作:/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/iterator:959:14: error : 不能从“const value_type”类型的左值(又名“const std::__1::basic_string”)转换为右值引用类型“reference”(又名“std::__1::basic_string &&”) ;类型不兼容 return static_cast(*__i); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    【解决方案3】:

    我认为这是不可能的。对于其他容器,我建议使用 std::move_iterator 适配器,但这不起作用,因为映射的键是 const。

    换句话说,您不能将元素一个一个地从地图中移出,因为这可能会更改键,而地图不允许这样做。

    而且没有办法从一张地图批量移动到另一张地图。列表支持拼接,但恐怕树不支持。

    【讨论】:

    • 我不太明白,底层类型是std::pair&lt;const key_type, value_type&gt;,为什么keys会改变?,我只是从temp中提取mapped_type并移动到m
    • 如果你想从地图元素中移动,那就是从那对元素开始的移动操作。但是你不能离开 const 的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    相关资源
    最近更新 更多