指针或索引
Pointers or Indexes?
我有一个类似网络的数据结构,由连接在一起的节点组成。节点的数量将发生变化,这些节点将不按特定顺序存储在std::vector<Node>
中,其中Node
是一个适当的类。
我想跟踪节点之间的链接。同样,这些链接的数量会发生变化,我正在考虑再次使用std::vector<Link>
。Link
类必须包含有关它所连接的两个节点的信息,以及其他链接功能。
Link
是否应包含
- 指向两个节点的两个指针
- 两个整数,用作
std::vector<Node>
- 或者我应该采用不同的系统(为什么?)
第一种方法虽然可能更好,但有问题,因为每次我从网络中添加或删除节点时都必须重新生成指针,但另一方面,这将使我免于将节点存储在随机访问容器中。
这通常很难回答。有各种性能和易用性的权衡。
使用指针可以为某些操作提供更方便的用法。例如
link.first->value
与。
nodes[link.first].value
使用指针可以提供比索引更好或更差的性能。这取决于各种因素。您需要进行测量,以确定在您的情况下哪个更好。
如果可以保证只有一定数量的节点,则使用索引可以节省空间。然后,您可以为索引使用较小的数据类型,而对于指针,无论您有多少节点,都需要使用完整的指针大小。使用较小的数据类型可以在单个缓存行中容纳更多的链接,从而提高性能。
使用索引复制网络数据结构会更容易,因为您不必重新创建链接指针。
具有指向std::vector
的元素的指针可能容易出错,因为矢量可能会在插入后将元素移动到内存中的另一个位置。
使用索引可以进行边界检查,这样可以更容易地发现一些错误。
使用索引使序列化更加简单。
尽管如此,我经常发现指数是总体上的最佳选择。使用方便的方法可以克服索引在语法上的许多不便,并且可以在指针具有更好性能的某些操作期间将索引切换到指针。
指定要使用或创建的类的接口。编写单元测试。做最简单的事情来完成单元测试。
所以它取决于类的接口。例如,如果Link
不导出有关节点的信息,那么选择什么方法并不重要。另一方面,如果您选择指针,请考虑std::shared_ptr。
我会向Node类添加一个(或多个)link
指针,然后手动维护链接。这将使您不必使用额外的容器。
如果你正在寻找更结构化的东西,你可以尝试使用Boost Intrusive。这以一种更普遍的方式有效地做了同样的事情。
如果使用,则可以完全避免Link
类
struct Node
{
std::vector<Node*> parents;
std::vector<Node*> children;
};
通过这种方法,
- 您可以避免创建另一个类
- 您的内存需求减少了
- 您必须进行较少的指针遍历才能遍历
Node
s的网络
下行。你必须确保:
- 创建或删除链接时,必须更新两个对象
- 删除
Node
时,必须从其parents
和children
中删除指向它的指针
您可以将其设为std::vector<Node *>
而不是std::vector<Node>
,并使用new
分配节点。
然后:
-
您可以将指向节点的指针存储在
Link
类中,而不用担心它们会成为无效的 -
您仍然可以在节点向量中随机访问它们。
不利的一面是,当它们从节点列表中删除时,您需要记住delete
。
我对类图结构中的向量的个人经验提出了这些不变量。
不要将数据存储在向量中,因为其他类都有指针/引用
你有一个类似图表的数据结构。如果代码不是性能关键型的(这与性能敏感型不同!),则不应考虑缓存压缩数据结构。
-
如果你不知道你的图有多大,并且你已经在一个向量中获得了
Node
数据,那么一旦你的向量调用vector::reallocate()
,所有迭代器和指针都将无效,这意味着你必须以某种方式重新生成整个数据结构,也许你必须创建所有数据结构的副本,并使用dfs或类似方法来调整指针。如果您想要移除某个向量中间的数据,也会发生同样的事情。 -
如果你知道你的数据会有多大,你就会坚定地保持这种状态,否则一旦你重新考虑,你就会头疼不已。
不要使用共享指针来跟踪需要释放的内容
如果你有一个类似图形的数据结构,并且你在性能关键路径上进行删除,那么每当你的算法决定他不再需要数据时,调用delete是不明智的。一种可能性是将数据保留在堆上(如果它是性能关键型的,请考虑使用池分配器)标记在性能关键部分不再需要的对象(如果你真的需要节省空间,可以考虑使用指针标记),或者在之后使用一些简单的标记和扫描算法来查找不再需要的项目(是的,图算法就是sutter所说的垃圾收集比智能指针更快的情况之一)。
请注意,对象的延迟销毁意味着您失去了Node类中所有类似RAII的功能。
- 当该数组的索引中没有元素时,指针指向什么?
- 通过指针与数组引用扩展数组索引序列
- C++ STL 数据结构常时按索引推送/弹出/随机访问,并具有指向元素的可靠指针
- 矢量指针索引处的读取元素
- 通过在编译时折叠带有索引的指针来分配 C 数组
- C++娜娜 如何从全局列表框*指针访问列表框内的索引 0 上的按钮?
- 是否可以创建带有索引但没有指针的单个链表?
- 创建一个没有指针但有索引的链表
- 运行时错误:基0x000000000000溢出到0xffffffffffffffff的指针索引表达式 (basic_st
- 如何查找指向数组中元素的指针的索引
- 如何使用 C+ 中的指针访问数组中的特定索引
- 从指针数组中的地址索引
- 混合索引和指针算术时避免使用C4365,而无需铸造
- 如何在指针初始化为数组的第一个索引后释放指针
- 基于索引的 alloca 返回的指针访问和"placement new"的效果
- 是否可以使用一系列智能指针来自动通过其索引更新其值
- 指针数组总是从索引C 生成一个
- 将指针分配给字符串对象的第一个也是最后一个索引
- 为对象指针数组的每个空索引创建新对象
- 如何索引指向数组 [queue] 的指针数组