4

我不是 C++ 和 STL 方面的专家。

我使用 Map 中的结构作为数据。关键是一些 C1 类。我想访问相同的数据,但也使用不同的密钥 C2(其中 C1 和 C2 是两个不相关的类)。

在不复制数据的情况下这可能吗?我尝试在谷歌中搜索,但很难找到我能理解的答案。

这适用于不支持 boost 库的嵌入式目标。

有人可以提供帮助吗?

4

7 回答 7

4

您可以将指向的指针存储为值,并且可以有两个具有不同键的映射指向相同的数据。Datastd::map

在这种共享数据所有权的情况下,我认为像这样的智能指针std::shared_ptr是一个不错的选择:

#include <map>       // for std::map
#include <memory>    // for std::shared_ptr

....

std::map<C1, std::shared_ptr<Data>> map1;
std::map<C2, std::shared_ptr<Data>> map2;

的实例Data可以使用std::make_shared().

于 2013-07-16T10:19:16.980 回答
3

不在标准库中,但 Boost 提供boost::multi_index

于 2013-07-16T10:11:22.263 回答
3

两个不同类型的键

我必须承认我读错了一点,并没有真正注意到你想要 2 个不同类型的键,而不是值。不过,解决方案将基于以下内容。其他答案几乎需要什么,我只想补充一点,您可以制作一个通用查找函数:(C++ 14-ish 伪代码)。

template<class Key> 
auto lookup (Key const& key) { }

并将其专门用于您的密钥(可以说比 SFINAE 更容易)

template<>
auto lookup<KeyA> (KeyA const& key) { return map_of_keys_a[key]; }

对于KeyB.

如果您想将其封装在一个类中,一个明显的选择是更改lookupoperator[].


相同类型的键,但不同的值

理念一

我能在 60 秒内想到的最简单的解决方案:(最简单的意思就是应该真正考虑清楚)。我也会切换到unordered_map默认值。

map<Key, Data> data;
map<Key2, Key> keys;

通过 访问data[keys["multikey"]]

这显然会浪费一些空间(复制Key类型的对象),但我假设它们比Data类型小得多。

想法 2

另一种解决方案是使用指针;那么重复的唯一成本是一个(智能)指针:

map<Key, shared_ptr<Data>> data;

Data只要至少有一个键指向它,对象 of就会存在。

于 2013-07-16T10:11:34.393 回答
2

在这些情况下,我通常做的是使用非拥有的指针。我将数据存储在向量中:

std::vector<Data> myData;

然后我将指针映射到每个元素。但是,由于向量的未来增长可能导致指针失效,因此我将在这种情况下选择使用向量索引。

std::map<Key1, int> myMap1;
std::map<Key2, int> myMap2;

不要将数据容器暴露给您的客户。将元素的插入和移除封装在特定的函数中,即处处插入,处处移除。

于 2013-07-16T10:15:03.233 回答
1

您可以考虑拥有一个std::list保存所有数据的普通对象,然后各种std::map对象将任意键值映射到指向列表的迭代器:

std::list<Data> values;
std::map<C1, std::list<Data>::iterator> byC1;
std::map<C2, std::list<Data>::iterator> byC2;

即,您使用普通的迭代器,而不是摆弄或多或少的原始指针。并且迭代器std::list具有很好的失效保证。

于 2013-07-16T10:23:51.277 回答
1

Bartek 的“想法 1”很好(尽管没有令人信服的理由更喜欢unordered_mapmap

或者,您可以使用std::map<C2, Data*>, 或std::map<C2, std::map<C1, Data>::iterator>允许在单键搜索后直接访问Data对象C2,但是您需要更加小心,不要访问无效(已擦除)Data(或者更准确地说,erase从两个容器原子的角度来看)任何其他用户)。

一个或两个maps 也可以迁移到-如果这对所有权有帮助shared_ptr<Data>,另一个可以使用。weak_ptr<>(这些在 C++11 标准中,否则明显的来源 - boost - 显然不适合你,但也许你已经实现了自己的库或选择了另一个库?现代 C++ 的基本类)。

编辑 - 哈希表与平衡二叉树

这与问题并不特别相关,但在下面收到了评论/兴趣,我需要更多空间来正确解决它。几点:

1) Bartek 不经意地建议在mapunordered_map推荐影响研究迭代器/指针失效的情况下进行更改是危险的,并且没有理由认为它是必要的(问题没有提到性能)并且没有推荐配置文件。

3) 程序中相对较少的数据结构对性能关键行为很重要,并且很多时候,一个与另一个的相对性能无关紧要。支持这一说法 -std::map在 C++11 之前编写了大量代码以确保可移植性,并且执行得很好。

4)当性能是一个严重的问题时,建议应该是“Care => profile”,但说经验法则是可以的 - 符合“不要过早地悲观”(参见例如 Sutter 和 Alexandrescu 的 C++ 编码标准) - 如果在这里被要求提供一个,我很乐意unordered_map默认推荐 - 但这并不是特别可靠。这是一个远离推荐std::map我看到改变的每一种用法的世界。

5) 这个容器性能侧轨已经开始引入有用的洞察力的临时片段,但远非全面或平衡。这个问题不是进行此类讨论的明智场所。如果有另一个问题可以解决这个问题,继续讨论是有意义的,并且有人要求我加入,我会在接下来的一两个月的某个时间做。

于 2013-07-16T10:18:31.523 回答
0

我有同样的问题,起初拿着两个地图共享指针听起来很酷。但是您仍然需要管理这两个地图(插入、删除等)。

比我想出其他方法来做到这一点。我的理由是;使用 xy 或半径角度访问数据。认为每个点都将保存数据,但点可以描述为笛卡尔 x,y 或 radius-angle 。

所以我写了一个类似的结构

struct MyPoint
{
    std::pair<int, int> cartesianPoint;
    std::pair<int, int> radianPoint;

    bool operator== (const MyPoint& rhs)
    {
         if (cartesianPoint == rhs.cartesianPoint || radianPoint == rhs.radianPoint)
             return true;
         return false;
    }
}

之后我可以用它作为钥匙,

std::unordered_map<MyPoint, DataType> myMultIndexMap;  

我不确定您的情况是否与此场景相同或可调整,但它可以作为一种选择。

于 2015-01-03T13:46:35.547 回答