简体   繁体   中英

Deallocation in C++ (Array of Vector of Pointers)

Ok, so I am creating a Graph class, I am hoping to be able to run algorithms on and maybe add a gui to later on this summer when I have some free time. Right now I have an adjList that is implemented as an array of vectors (one for each vertex), each vector is a list of pointers representing edges going from each associated vertex to other vertices. It is declared as a protected member of my Graph class like so:

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

I have a side question. Now here I have an array (through a pointer) of vectors that hold pointers. If instead this was not an array, but rather a pointer to just a single vector of node pointers then I could call the constructor like so:

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

This would allow me to specify a default size for the dynamic array in the vector, but it seems I cannot call the constructor, or at least can't get the syntax right when I have an array.

Now for my main concern. For each of these vectors in my pointer array I add a number of node pointers to each vector using a call to the new operator in my addVertex method. Now I need to make sure I handle deallocation of all this correctly. I believe I have an understanding of how this should work in C++, but I know pointers are tricky so I wanted to get someone to take a look before I go on adding lots to this code base. I couldn't find anything with a few searches that was quite like what I have. Here is my deallocation:

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

Will this get free all of the memory. Also is there an easy way for me to verify this for sure, eg. to keep a count of how much memory has been allocated using new while I am debugging?

[EDIT: Update w/ more info]

Here is a link to Google Books showing one of the algorithms I am wanting to implement given in psuedocode. This version of breadth-first search operates on an adjacency list, (an array of lists of pointers). Pointers must be used because of the attributes that are assigned to each node using the adjacency list.

I am wanting to retain these attributes from my BFS algorithm stored to with each node after it is ran. I know it is possible to do this in other ways, perhaps indexing nodes and using parallel arrays to store the attributes. But I wanted to have code that worked similar to this psuedo-code (for BFS in the link).

  1. Why are you using an array of vectors?
  2. Why are you maintaining a pointer to a vector?
  3. Why are you maintaining a vector of pointers?

All three of those decisions cost you and directly negate the memory-managing ability of the vector class. A vector is not simply an array that can grow under the covers, it also manages memory for you via a pattern known as RAII .

When you create a vector of pointers the vector cannot clean up the memory that the pointers refer to upon destruction, so you still need to call delete on every element of the vector.

When you create a pointer to a vector you cannot take advantage of the fact that the vector deallocates any memory it has allocated in its destructor. Thus, once again, you negate the vector's ability to manage memory for you as you must call delete on the vector in order to prevent a memory leak.

When you maintain an array of vectors... well, you're already using vectors, why not just use a vector<vector<T>> ?

The vector type dynamically allocated memory for you behind the scenes specifically to avoid the sort of issues you are encountering now. Sure, you can manage your own memory (you simply deallocate in the opposite order that you allocated, which you seem to grasp), but why bother when there are mechanisms in place to do it for you?

I don't understand the design goal here. Why not simply use a vector<vector<Edge>> and rid yourself of these problems entirely?

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

If you are building a class with a lot of indexing to internal objects through pointers, one way to ensure you delete objects at memory locations only once is to keep a memory pool. For example, you can have a std::vector<Node*> Graph::memPool member. When deleting the Graph , just delete everything in Graph::memPool and not the indexes in the individual node's adjList . Whenever a new node is created, just add it to the memory pool.

In your current example, if two nodes have an edge to the same node, you may delete an invalid memory location.

Another alternative is to use numbered indexes instead of pointers. The graph has a master vector of nodes while the adjacency list in each node keeps vector indexes.

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

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

No explicit dellocation is necessary in this case. Similar to using pointers, removing nodes from the graph will require scanning the adjacency lists for updating of indexes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM