我不是 C++ 和 STL 方面的专家。
我使用 Map 中的结构作为数据。关键是一些 C1 类。我想访问相同的数据,但也使用不同的密钥 C2(其中 C1 和 C2 是两个不相关的类)。
在不复制数据的情况下这可能吗?我尝试在谷歌中搜索,但很难找到我能理解的答案。
这适用于不支持 boost 库的嵌入式目标。
有人可以提供帮助吗?
您可以将指向的指针存储为值,并且可以有两个具有不同键的映射指向相同的数据。Data
std::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()
.
不在标准库中,但 Boost 提供boost::multi_index
我必须承认我读错了一点,并没有真正注意到你想要 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
.
如果您想将其封装在一个类中,一个明显的选择是更改lookup
为operator[]
.
我能在 60 秒内想到的最简单的解决方案:(最简单的意思就是应该真正考虑清楚)。我也会切换到unordered_map
默认值。
map<Key, Data> data;
map<Key2, Key> keys;
通过 访问data[keys["multikey"]]
。
这显然会浪费一些空间(复制Key
类型的对象),但我假设它们比Data
类型小得多。
另一种解决方案是使用指针;那么重复的唯一成本是一个(智能)指针:
map<Key, shared_ptr<Data>> data;
Data
只要至少有一个键指向它,对象 of就会存在。
在这些情况下,我通常做的是使用非拥有的指针。我将数据存储在向量中:
std::vector<Data> myData;
然后我将指针映射到每个元素。但是,由于向量的未来增长可能导致指针失效,因此我将在这种情况下选择使用向量索引。
std::map<Key1, int> myMap1;
std::map<Key2, int> myMap2;
不要将数据容器暴露给您的客户。将元素的插入和移除封装在特定的函数中,即处处插入,处处移除。
您可以考虑拥有一个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
具有很好的失效保证。
Bartek 的“想法 1”很好(尽管没有令人信服的理由更喜欢unordered_map
)map
。
或者,您可以使用std::map<C2, Data*>
, 或std::map<C2, std::map<C1, Data>::iterator>
允许在单键搜索后直接访问Data
对象C2
,但是您需要更加小心,不要访问无效(已擦除)Data
(或者更准确地说,erase
从两个容器原子的角度来看)任何其他用户)。
一个或两个map
s 也可以迁移到-如果这对所有权有帮助shared_ptr<Data>
,另一个可以使用。weak_ptr<>
(这些在 C++11 标准中,否则明显的来源 - boost - 显然不适合你,但也许你已经实现了自己的库或选择了另一个库?现代 C++ 的基本类)。
编辑 - 哈希表与平衡二叉树
这与问题并不特别相关,但在下面收到了评论/兴趣,我需要更多空间来正确解决它。几点:
1) Bartek 不经意地建议在map
不unordered_map
推荐影响研究迭代器/指针失效的情况下进行更改是危险的,并且没有理由认为它是必要的(问题没有提到性能)并且没有推荐配置文件。
3) 程序中相对较少的数据结构对性能关键行为很重要,并且很多时候,一个与另一个的相对性能无关紧要。支持这一说法 -std::map
在 C++11 之前编写了大量代码以确保可移植性,并且执行得很好。
4)当性能是一个严重的问题时,建议应该是“Care => profile”,但说经验法则是可以的 - 符合“不要过早地悲观”(参见例如 Sutter 和 Alexandrescu 的 C++ 编码标准) - 如果在这里被要求提供一个,我很乐意unordered_map
默认推荐 - 但这并不是特别可靠。这是一个远离推荐std::map
我看到改变的每一种用法的世界。
5) 这个容器性能侧轨已经开始引入有用的洞察力的临时片段,但远非全面或平衡。这个问题不是进行此类讨论的明智场所。如果有另一个问题可以解决这个问题,继续讨论是有意义的,并且有人要求我加入,我会在接下来的一两个月的某个时间做。
我有同样的问题,起初拿着两个地图共享指针听起来很酷。但是您仍然需要管理这两个地图(插入、删除等)。
比我想出其他方法来做到这一点。我的理由是;使用 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;
我不确定您的情况是否与此场景相同或可调整,但它可以作为一种选择。