我经常遇到以下情况。 (不失一般性:我在以下示例中使用了两个容器的最简单的可能情况,但在几何算法的实现中,需要大量的描述互连图形数据结构。)
我有两个数据类型A
和B
的大量值,它们相互引用(通常不是一对一),比如说,首先是通过(本机)指针或引用。它们都放置在容器using CA = std::container1< A >;
和using CB = std::container2< B >;
中。某些函数的结果是一对CA
和CB
个实例。拥有CA
实例的元素我想删除CB
实例中的引用元素,反之亦然。
struct A;
struct B;
using CA = std::container1< A >;
using CB = std::container2< B >;
我想将A
和B
定义如下:
struct A
{
int payload;
typename CB::iterator pb; // hard error here in general case of choosing `std:container2`
};
struct B
{
double payload;
typename CA::iterator pa;
};
// ...
PA a;
PB b;
// ...
assert(!a.empty());
assert(a.begin()->pb != b.end()); // and pb is not default-constructed
b.erase(a.begin()->pb);
但目前我无法在一般情况下声明typename CB::iterator pb;
,只是B /*const*/ * pb;
或B /*const*/ & pb;
,因为B
类型是{CB
的一部分1}}声明,在将容器typedef iterator
的成员CB
用于聚合A
的定义时不完整。
有一个不完整类型的容器的提议,但它目前不是标准的一部分。
对于 libstdc ++ 和 libc ++ 中当前实现的非调试容器版本,上面的代码可能会被编译得很好,但它根本不是强制性的。如果成功,迭代器的定义除了指针或对value_type
的引用之外不包含任何内容。但是标准中没有要求这样做。
正如您在live example中看到的那样,std::unordered_set
存在严重错误,因为其迭代器需要std::hash
value_type
为完整类型。
由于体系结构(OOP)和性能原因,建议注释中的双重间接可能不是一个好的解决方案。至少看起来很难看std::container3< B * >
和std::container2< B >
,并跟踪不同交叉引用容器的结果动物园的有效性。
迭代器本质上具有指针语义。并且他们不应该要求参考类型的完整性。
如何处理C++14
及之前的问题?
答案 0 :(得分:2)
我使用vector
,list
,deque
,set
和unordered_set
尝试了第二个示例。仅对于unordered_set
我得到了一个编译器错误,我可以通过使用指针容器来修复:
using CA = std::unordered_set< A* >;
using CB = std::unordered_set< B* >;
参见here(Ideone.com C ++ 14)。
答案 1 :(得分:1)
疯狂的解决方案是存储对齐的存储并手动管理迭代器的对象生命周期,静态断言使存储的大小合适。
这是一种真正的痛苦而且非常不安全(容易犯错误),但它确实有效。
使用无聊容器迭代器的大小/对齐方式。通过adl使用免费功能访问迭代器。
std
往往过度需要完全定义的类型。
仔细使用crtp和标签可能会让你自动化危险的代码,但很棘手。
答案 2 :(得分:-1)
在您的实际示例中,基本上您所拥有的是:int
和double
之间的关系为1:1,整数存储在vector<int>
中,双打存储在unordered_set<double>
中unordered_map<double, int>
。
一条路径可能是简化问题,例如:你能将数据放入fs
吗?有时这可能是真的,并将解决很多努力。有时这可能不是真的,例如您可能需要按整数对数据进行排序。
我认为使用std 2容器的路径充满了困难,你的编译错误只是冰山一角,例如:
另一条路径可能是:考虑使用boost bimap或multi_index之类的东西。他们利用这样一个事实,即如果你想要两个基于节点的结构(例如两个集合)具有1:1的关系,那么对于插入它只需要进行一个包含两个节点的分配