【问题标题】:Deallocation in C++ (Array of Vector of Pointers)C++ 中的释放(指针向量数组)
【发布时间】:2012-05-11 13:18:21
【问题描述】:

好的,所以我正在创建一个 Graph 类,我希望能够在今年夏天晚些时候有空闲时间的时候运行算法并添加一个 gui。现在我有一个 adjList,它被实现为一个向量数组(每个顶点一个),每个向量都是一个指针列表,表示从每个相关顶点到其他顶点的边。它被声明为我的 Graph 类的受保护成员,如下所示:

std::vector <Node*> *adjList;
adjList = new std::vector<Node*>[V];

我有一个附带问题。现在在这里我有一个包含指针的向量数组(通过指针)。相反,如果这不是一个数组,而是一个指向单个节点指针向量的指针,那么我可以像这样调用构造函数:

adjList = new std::vector<Node*>(10);

这将允许我为向量中的动态数组指定默认大小,但似乎我无法调用构造函数,或者至少在我有数组时无法正确获取语法。

现在我主要关心的是。对于指针数组中的每个向量,我在 addVertex 方法中调用 new 运算符,为每个向量添加多个节点指针。现在我需要确保我正确处理所有这些的释放。我相信我对这在 C++ 中应该如何工作有所了解,但我知道指针很棘手,所以在我继续向这个代码库添加大量内容之前,我想找人看看。通过几次搜索,我找不到任何与我所拥有的非常相似的东西。这是我的释放:

for(int i =0; i < V; i++)
    for (unsigned int j = 0; j < adjList[i].size(); j++)
        delete adjList[i][j];
delete adjList;

这会释放所有内存吗?还有一种简单的方法可以让我确定这一点,例如。在调试时使用 new 计算分配了多少内存?

[编辑:更新更多信息]

这是 Google Books 的link,显示了我希望在伪代码中实现的算法之一。此版本的广度优先搜索在邻接列表(指针列表数组)上运行。由于使用邻接表分配给每个节点的属性,因此必须使用指针。

我希望在运行后将这些属性从我的 BFS 算法存储到每个节点中。我知道可以通过其他方式做到这一点,也许是索引节点和使用并行数组来存储属性。但我希望拥有与此伪代码类似的代码(用于链接中的 BFS)。

【问题讨论】:

  • 为什么要使用向量数组?如果您已经在使用它们,为什么不使用向量的向量?
  • 我似乎将其更改为向量向量,但我仍然很好奇如果我确实需要使用向量数组,我将如何调用构造函数。看来我只能调用默认构造函数了。

标签: c++ memory pointers memory-management vector


【解决方案1】:
  1. 为什么要使用向量数组?
  2. 为什么要维护指向向量的指针?
  3. 为什么要维护指针向量?

所有这三个决定都会让您付出代价,并直接否定向量类的内存管理能力。向量不仅仅是一个可以在后台增长的数组,它还通过称为RAII 的模式为您管理内存。

当您创建一个指针向量时,该向量无法清理指针在销毁时引用的内存,因此您仍然需要对向量的每个元素调用delete。

当您创建指向向量的指针时,您无法利用向量释放它在其析构函数中分配的任何内存这一事实。因此,您再次否定了向量为您管理内存的能力,因为您必须在向量上调用 delete 以防止内存泄漏。

当您维护一个向量数组时...好吧,您已经在使用向量了,为什么不直接使用vector&lt;vector&lt;T&gt;&gt;?

vector 类型在幕后为您动态分配内存,专门用于避免您现在遇到的那种问题。当然,您可以管理自己的内存(您只需按照与分配相反的顺序解除分配,您似乎掌握了这一点),但是当有适当的机制可以为您执行此操作时,何必费心呢?

我不明白这里的设计目标。为什么不简单地使用vector&lt;vector&lt;Edge&gt;&gt; 并彻底摆脱这些问题?

class Edge {
    // whatever
}

class Graph {
private:
    // when instances of this class go out of scope, 
    // all of the memory allocated to these vectors is deallocated for you!
    vector<vector<Edge>> vertices;  
}

【讨论】:

  • 很抱歉回复晚了。工作了一段时间后,我昨天很早就昏倒了。看来我没有提供足够的信息。由于我在 OP 中更新的原因,我以我的方式实现了这一点
  • 至于为什么我不使用向量的向量,我想我可以。
  • @CoryGross:好的,那是真的,那么你只需要在顶级向量超出范围之前释放每个子向量的每个元素。有时使用指针向量是有充分理由的,但它们很少见,而且通常没有必要。
【解决方案2】:

如果您正在构建一个通过指针对内部对象进行大量索引的类,那么确保仅在内存位置删除对象一次的一种方法是保留一个内存池。例如,您可以有一个std::vector&lt;Node*&gt; Graph::memPool 成员。删除Graph 时,只需删除Graph::memPool 中的所有内容,而不是单个节点adjList 中的索引。每当创建新节点时,只需将其添加到内存池即可。

在您当前的示例中,如果两个节点与同一个节点有一条边,您可能会删除无效的内存位置。

另一种选择是使用编号索引而不是指针。该图有一个节点的主向量,而每个节点中的邻接表保持向量索引。

class Graph
{
    std::vector<Node> all_nodes;
    ...
};

struct Node
{
    std::vector<size_t> adjList;
    SomeDataType nodeData;//e.g. node cost, weight, reward, etc
    ...
};

在这种情况下,不需要显式解除分配。与使用指针类似,从图中删除节点需要扫描邻接表以更新索引。

【讨论】:

    猜你喜欢
    • 2022-01-18
    • 2011-07-18
    • 2020-04-15
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-18
    相关资源
    最近更新 更多