我正在为C ++中的路径查找算法实现图结构。
当创建新的边或节点时,它将存储在单独的向量中,以便稍后由图类的析构函数删除。我使用指针因为它们提供了简单的图形导航;我可以通过简单地比较它们的地址来轻松测试节点的身份,或者我可以通过创建指针向量来创建路径,然后直接使用这些指针来浏览图形。
struct Edge
{
Node* from;
Node* to;
}
struct Node
{
Data data;
std::vector<Edge*> outEdges;
std::vector<Edge*> inEdges;
}
我读过关于指针是如何坏的文章,应该避免或用智能指针代替(但即使应该避免使用)。或者说优秀的程序员根本不使用它们(有例外)。我知道它们是内存泄漏的来源,安全风险并且整体难以正确管理(特别是在多线程应用程序中)。
我的问题:在这种情况下指针方法不好吗?
编辑1: 有些问题我应该避免在哪里读到关于指针(智能)的内容。 https://softwareengineering.stackexchange.com/questions/56935/why-are-pointers-not-recommended-when-coding-with-c/163279#163279
在他的回答的第二部分:
答案 0 :(得分:4)
我要重复一遍。指针并不坏。用友好的黄色字母(C)打印并钉在墙上。它们非常有用。我从未见过专业的C ++程序,它设法完全避免指针。
管理自己的指针通常很糟糕,除非你正在使用指针管理器。
无约束的标准内存分配可能是高性能应用程序的瓶颈 - 但指针不是标准内存分配的同义词。
指针不是内存泄漏或安全风险的来源。指针并不难管理(一般来说,写出好的程序并不困难。)
如果您不想使用指针,则选择错误的语言。
答案 1 :(得分:1)
为什么出于性能原因可能会避免使用指针?
因为你必须在内存中跟随它们,所以它们会遇到非常糟糕的缓存局部性。
有多少拥有者可以拥有一个物体?
只能有一个!
除非它是shared_ptr
(然后是真正的单所有者)。因此,只要您只关注它们并且不删除或转移所有者随附它们,您就可以使用非拥有指针。
如果我指向什么移动,指针会神奇地更新吗?
没有!如果您使用向量进行存储并且超出其容量,它将重定位呈现所有指向它的指针无效。如果确定您有足够的容量,则可以使用指针。
所以在这种情况下我会考虑以下结构,一个指向内存的指针只是一个内存索引,为什么不自己使用索引呢?
struct Edge {
// index into allNodes
uint32_t from;
uint32_t to;
}
std::vector<Edge> allEdges;
struct Node {
Data data;
// index into allEdges
std::vector<uint32_t> outEdges; // sort on to
std::vector<uint32_t> inEdges; // sort on from
}
std::vector<Node> allNodes; // contains all nodes
如果你不需要遍历所有边缘,那么或者更根本
struct Node {
Data data;
// index into allNodes
std::vector<uint32_t> outEdges; // sort
std::vector<uint32_t> inEdges; // sort
}
std::vector<Node> allNodes; // contains all nodes
你不能做的是:
a)删除任何节点/边缘并移动其余部分。
b)移动其中任何一个,包括
c)对它们进行排序
如果删除它,请记住擦除两个节点中的Edge。
如果你在每个向量中有很多边缘,那么对它们进行排序可能是相关的,这样你就可以使用二进制搜索来找到一个特定的边缘。
如果要使用指针,请确保每个节点和边都有一个所有者。将它们放在一个向量中可以保证这一点,但要注意调整大小,因为它会使所有向量无效。
答案 2 :(得分:1)
在需要之前应该避免使用指针。
此处,节点包含其他节点或对它们的引用。在收容中,维持N对N节点之间的一致性将是一场噩梦。某种引用的复杂程度要低得多,也不太可能导致问题。
但现在管理所有权成为一个问题。谁拥有Node并且在不再使用时负责删除?
使用无向图,当Node没有进一步的连接时,Node可以拥有自己并自毁(delete
或从节点池中删除自己)。
在有向图中,节点无法自我确定,因为它不知道谁可能仍然指向它。当没有节点接触节点时,它的其他节点必须共同负责并释放节点。跟踪这是一个有趣的管理任务,但也是一个图表的点。
答案 3 :(得分:0)
使用Edge
类的普通指针是可以的,只要已添加的节点不再被删除。您仍然可以完整删除整个图表。如果您的图表经常变异,我建议您使用std::weak_ptr
作为边缘。
然而,课程Edge
已完全过时。
struct Node
{
Data data;
std::vector<Node*> edges;
}
这对于有向图和无向图是足够的。在这两种情况下,您只需要记录传出边缘。在无向图中,您必须在两个节点中记录边缘(指针在另一个方向上)。
答案 4 :(得分:-1)
关于指针坏的模因简直是假的。指针是语言的重要组成部分,通常是从另一个数据结构引用一个数据结构的最佳(或唯一)方式。甚至美国宇航局的JPL也在航天器的性能和安全关键代码中自由使用指针。查看他们的编程标准:http://lars-lab.jpl.nasa.gov/JPL_Coding_Standard_C.pdf
不小心使用指针会让你陷入困境,但生活中的一切都是如此。