图结构 - 指针坏了吗?

时间:2015-10-15 20:05:26

标签: c++ pointers

我正在为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

在他的回答的第二部分:

  • “C ++中指针的大多数用法都是不必要的。”
  • “......现代C ++习语通常根本不需要指针......”
  • “对于那些了解现代C ++的人来说,很明显你很少需要任何指针(智能或原始;除非将它们用作迭代器)。”

5 个答案:

答案 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

不小心使用指针会让你陷入困境,但生活中的一切都是如此。