代码之家  ›  专栏  ›  技术社区  ›  Setu

如何将元素从std::map移动到std::vector

  •  0
  • Setu  · 技术社区  · 5 月前

    我有一个 std::map 它包含一堆键值对。我想把这些元素移到 std::vector .我试着用 std::transform <algorithm> 这样做,但它不起作用。这是我的代码:

    #include <algorithm>
    #include <cstdint>
    #include <iostream>
    #include <map>
    #include <vector>
    
    struct Values
    {
            uint32_t a = 0;
            uint32_t b = 0;
    
            Values(uint32_t x, uint32_t y): a(x), b(y) {}
    };
    
    template <typename MapType>
    auto foo(MapType&& map)
    {
            std::vector<typename MapType::value_type> v;
            v.reserve(map.size());
    
            std::transform(map.begin(), map.end(), std::back_inserter(v), [](const auto& kv) -> decltype(auto) { return std::move(kv); });
            std::cout << map.size() << " " << v.size() << "\n";
    }
    
    int main()
    {
            std::map<uint32_t, Values> data;
            for(uint32_t i = 0; i < 100; i++)
                    data.emplace(std::piecewise_construct, std::forward_as_tuple(i), std::forward_as_tuple(2*i, 3*i));
    
            foo(std::move(data));
    
            return 0;
    }
    

    我正在使用编译此代码 gcc :

    g++ -std=c++23 -Ofast -Wall -Wextra -Wpedantic -Wconversion -Werror main.cpp
    

    这是编译器资源管理器的链接。

    程序输出 std::map std::矢量 致电后 std::转换 。我得到的输出是:

    100 100
    

    这告诉我,元素不是被移动,而是被复制到向量中。如何将此代码更改为使用move。

    2 回复  |  直到 5 月前
        1
  •  2
  •   Igor Tandetnik    5 月前

    你可以接近这样的东西:

    for (auto it = map.begin(); it != map.end(); /*no increment*/) {
      auto node = map.extract(it++);
      v.emplace_back(std::move(node.key()), std::move(node.mapped()));
    }
    

    这应该只涉及键和值对象上的移动构造函数,而不涉及复制构造函数(当然,对于那些两者不同的类;在你的例子中,移动和复制是等效的)。它将在最后使地图为空。

        2
  •  1
  •   Ahmed AEK    5 月前

    C++中的“moving”不会删除元素,它只是在使用它们创建新对象时使用move构造函数,对于普通类型,它只会复制它们,但对于包含以下资源的对象 unique_ptr vector 移动构造函数将正确地窃取托管资源,您可以声明一个移动构造函数来查看它是否被调用。

    最后,你不能动 const 对象(请参见move构造函数声明) const auto& kv 需要更改为 auto& kv 在你的 transform ,然后您需要清除“移出”对象的映射。

    #include <algorithm>
    #include <cstdint>
    #include <iostream>
    #include <map>
    #include <vector>
    
    struct Values
    {
        uint32_t a = 0;
        uint32_t b = 0;
        Values(const Values&) { std::cout << "copied!\n"; }
        Values(Values&&) { std::cout << "moved!\n"; }
        Values(uint32_t x, uint32_t y) : a(x), b(y) {}
    };
    
    template <typename MapType>
    auto foo(MapType&& map)
    {
        std::vector<typename MapType::value_type> v;
        v.reserve(map.size());
    
        std::transform(map.begin(), map.end(), std::back_inserter(v), [](auto& kv) -> decltype(auto) { return std::move(kv); });
        map.clear(); // clear map content which has been "moved from"
        std::cout << map.size() << " " << v.size() << "\n";
    }
    
    int main()
    {
        std::map<uint32_t, Values> data;
        for (uint32_t i = 0; i < 100; i++)
            data.emplace(std::piecewise_construct, std::forward_as_tuple(i), std::forward_as_tuple(2 * i, 3 * i));
    
        foo(std::move(data));
    
        return 0;
    }
    

    你会看到100 moved 打印有 auto& 和100 copied 打印有 const auto&