C ++中的释放(指针向量数组)

时间:2012-05-02 03:45:37

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

好的,所以我正在创建一个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;

这会释放所有内存吗?还有一种简单的方法让我可以肯定地验证这一点,例如。在我调试的时候,用新的数据来计算已经分配了多少内存?

[编辑:更新w / more info]

以下是Google图书的link,其中显示了我想在psuedocode中实现的算法之一。此版本的广度优先搜索在邻接列表(指针列表数组)上运行。必须使用指针,因为使用邻接列表为每个节点分配了属性。

我希望在运行后保存存储到每个节点的BFS算法中的这些属性。我知道可以通过其他方式执行此操作,可能是索引节点并使用并行数组来存储属性。但是我希望代码与这个伪代码类似(对于链接中的BFS)。

2 个答案:

答案 0 :(得分:2)

  1. 你为什么要使用矢量数组?
  2. 为什么要保持指向矢量的指针?
  3. 你为什么要维护一个指针向量?
  4. 所有这三个决策都会花费你并直接否定向量类的内存管理能力。向量不仅仅是一个可以在封面下成长的数组,它还通过称为RAII的模式为您管理内存。

    当你创建一个指针向量时,向量无法清除指针在破坏时引用的内存,所以你仍然需要在向量的每个元素上调用delete

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

    当你维护一个向量数组时......好吧,你已经在使用向量了,为什么不只使用vector<vector<T>>

    矢量类型为幕后动态分配内存,专门用于避免您现在遇到的问题。当然,你可以管理你自己的记忆(你只需要按照你所分配的相反顺序解除分配,你似乎已经掌握了这一点),但为什么在有适当的机制为你做准备时呢?

    我不明白这里的设计目标。为什么不简单地使用vector<vector<Edge>>并完全摆脱这些问题?

    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;  
    }
    

答案 1 :(得分:0)

如果要构建一个通过指针对内部对象进行大量索引的类,一种确保在内存位置删除对象的方法只有一次才能保留内存池。例如,您可以拥有std::vector<Node*> 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
    ...
};

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