用boost multi_index替换映射向量合理吗?

问题描述 投票:0回答:1

在我的应用程序中,我存储一个巨大的(!)容器:向量的向量。 每个向量都有一个唯一的名称,我使用映射来存储索引 到向量以进行进一步访问。需要将数据存储在向量中 在我的应用程序中,因为我必须进行大量处理,因此需要 快速访问其中的元素。

不幸的是 std::map 不关心插入顺序 在我的用例中很重要,我遇到了这个主题:

一个跟踪插入顺序的 std::map?

不幸的是,所提出的解决方案并不完全是我所需要的,我现在想知道:

  • 是否可以让boost_multi_index使用向量来存储数据?
  • 用 boost multi_index 替换矢量/地图使用是否合理(就我而言)或
  • 使用 bimap 或
  • 之类的东西
  • “我的问题”有更优雅的方式吗?

示例代码:

#include <vector>
#include <map>
#include <string>
#include <iostream>

using payload_t = std::vector<uint32_t>;
using container_t = std::vector<payload_t>;
using container_map_t = std::map<std::string, size_t>;

int main()
{
    container_t container;
    container_map_t container_map;

    // Store 1st payload
    container.push_back(std::move(payload_t{1,2,3}));
    container_map["One"] = container.size() - 1;

    // Store 2nd payload
    container.push_back(std::move(payload_t{4,5,6,7}));
    container_map["Two"] = container.size() - 1;

    // Store 3rd payload
    container.push_back(std::move(payload_t{8,9}));
    container_map["Three"] = container.size() - 1;

    // Iterating vector access
    for (auto& outer : container)
        for (auto& inner : outer)
            std::cout << inner;
    std::cout << std::endl << std::endl;

    // Direct vector access
    for (auto& inner : container[1])
        std::cout << inner;
    std::cout << std::endl << std::endl;

    // Access via name
    for (auto& inner : container.at(container_map.at("Two")))
        std::cout << inner;
    std::cout << std::endl << std::endl;

    // Iterating access via map; order not preserved
    for (auto& [key, vec] : container_map)
    {
        std::cout << key << ": ";
        for (auto& inner : container[vec])
            std::cout << inner;
        std::cout << std::endl;
    }

    return 0;
}
c++ boost c++17 multi-index boost-multi-index
1个回答
0
投票
  • 是否可以让boost_multi_index使用向量来存储数据?

不。所有容器都在基于节点的存储上实现,因此保证了迭代器/引用的稳定性。

  • 用 boost multi_index 替换矢量/地图使用是否合理(就我而言)[或]

似乎是这样,但请看下文。

  • 使用bimap之类的东西

我不清楚它将如何填补任何空白。

  • “我的问题”有更优雅的方式吗?

也许吧。最简单的胜利,IMO:

住在Coliru

#include <cassert>
#include <cstdint>
#include <map>
#include <vector>

#include <fmt/ranges.h>

using payload_t = std::vector<uint32_t>;
using map_t     = std::map<std::string, payload_t>;
using entry_t   = map_t::value_type;
using ref_t     = std::reference_wrapper<entry_t>;

template <> struct fmt::formatter<ref_t> {
    auto format(ref_t r, auto& ctx) const { return format_to(ctx.out(), "{}", r.get().first); }
};

int main() {
    map_t              container;
    std::vector<ref_t> index;

    auto insert = [&](std::string name, payload_t element) {
        auto [it, ok] = container.emplace(std::move(name), std::move(element));
        if (ok)
            index.push_back(*it);
        else
            assert(false); // TODO decide on how to behave
    };

    for (auto&& [name, data] : { std::tuple //
             {"One", payload_t{1, 2, 3}},
             {"Two", payload_t{4, 5, 6, 7}},
             {"Three", payload_t{8, 9}},
         })
    {
        insert(std::move(name), data);
    }

    fmt::print("All (order not preserved): {}\n", container);

    for (int i = 0; entry_t& inner : index)
        fmt::print("At #{}, {}: {}\n", i++, inner.first, inner.second);

    fmt::print("Access via name: {}\n", container.at("Two"));
}

印刷

All (order not preserved): {"One": [1, 2, 3], "Three": [8, 9], "Two": [4, 5, 6, 7]}
At #0, One: [1, 2, 3]
At #1, Two: [4, 5, 6, 7]
At #2, Three: [8, 9]
Access via name: [4, 5, 6, 7]
© www.soinside.com 2019 - 2024. All rights reserved.