分配结构列表的向量

Allocate vector of list of structs

本文关键字:向量 列表 结构 分配      更新时间:2023-10-16

我有一个类,它有一个成员,该成员是结构列表的向量,我想动态分配列表和列表中的元素。我不确定为什么,但由于某种原因,即使我添加了元素,我的列表似乎也是空的。

这是代码:

#include <iostream>
#include <vector>
#include <list>
using namespace std;
template <class Weight>
class Graph {
private:
    struct Edge {
        int node;
        Weight weight;
    };
    vector<list<Edge>> nodes;
public:
    Graph(int numberOfNodes) {
        int i;
        for (i=0; i < numberOfNodes; ++i) {
            nodes.push_back(*(new list<Edge>));
        }
    }
    void addEdge(int nodeA, int nodeB, Weight weight, bool bothWays= false) {
        if (bothWays) {
            addEdge(nodeB, nodeA, weight);
        }
        list<Edge> edgesA= nodes.at(nodeA);
        Edge *edge= new Edge;
        edge->node = nodeB;
        edge->weight = weight;
        edgesA.push_back(*edge);
    }

    void print() {
        unsigned int i;
        list<Edge> edges;
        for(i=0; i < nodes.size(); ++i) {
            cout << "Node " << i << ". Edges: ";
            edges= nodes.at(i);
            typename list<Edge>::iterator iterator = edges.begin();
            typename list<Edge>::iterator end = edges.end();
            for (; iterator != end; ++iterator) {
                cout << "Node " << iterator->node << ". Weight: " << iterator->weight;
            }
            cout << endl;
        }
    }
};

Graph<int> generateRandomGraph(int numberOfNodes) {
    Graph<int> g(numberOfNodes);
    int i, j, weight=22;
    for(i=0; i < numberOfNodes; ++i) {
        for(j=i; j < numberOfNodes; j++) {
            g.addEdge(i, j, weight, true);
        }
    }
    return g;
}

int main() {
    Graph<int> g= generateRandomGraph(3);
    g.print();
}

它正在打印这个:

Node 0. Edges: 
Node 1. Edges: 
Node 2. Edges: 

好像列表是空的。 试图使用调试找出问题所在,但没有运气。我来自ANSI C背景,我仍然不确定新关键字的工作原理。我应该在向量中存储指向列表的指针吗?我应该在列表中存储指向结构的指针吗?

此外,如果答案还可以提供如何在类的析构函数上释放内存,我将不胜感激。

注意:模板是为了让我的图表上的权重可以定义为 int 或 float。

编辑:我只想补充一点,我以前没有使用任何硬编码指针。您在这里看到的代码是我经过几个小时的反复试验后得到的代码,以使其正常工作。

Graph(int numberOfNodes) 
{
    int i;
    for (i=0; i < numberOfNodes; ++i) 
    {
        //nodes.push_back(*(new list<Edge>));
                            ^^^^^^^^^^^^^^ memory leak
       nodes.push_back(list<Edge>()); // adds an empty list to the vector
    }
}

这修复了内存泄漏#1。

list<Edge> edgesA= nodes.at(nodeA);
Edge *edge= new Edge;
edge->node = nodeB;
edge->weight = weight;
edgesA.push_back(*edge);
                 ^^^^^ memory leak

要修复它:

list<Edge> edgesA= nodes.at(nodeA);
Edge edge; // no need for heap allocation!
edge.node = nodeB;
edge.weight = weight;
edgesA.push_back(edge);

iterator 对于迭代器变量名称来说是一个糟糕的名称。

void print() 
{
    std::for_each(nodes.begin(), nodes.end(), [](const list<Edge>& l)
    {
        std::for_each(l.begin(), l.end(), [](const Edge& e)
        {
            std::cout << "Node " << e.node << ". Weight: " << e.weight;
        });
        std::cout << std::endl;
    });
}

这应该修复您的输出。

您还将对列表的副本而不是实际列表进行操作:

list<Edge> edgesA= nodes.at(nodeA);

您应该将其声明为:

list<Edge>& edgesA= nodes.at(nodeA);
//        ^^ This makes it a reference instead of a copy

如注释中所述,此处的内存管理存在许多问题,但边缘列表保持为空的原因是 addEdge(...) 中的代码。

如果将其更改为以下内容:

void addEdge(int nodeA, int nodeB, Weight weight, bool bothWays= false) {
    if (bothWays) {
        addEdge(nodeB, nodeA, weight);
    }
    Edge edge;
    edge.node = nodeB;
    edge.weight = weight;
    nodes.at(nodeA).push_back(edge);
}

您将摆脱内存管理问题之一,并且还具有边缘列表。 为清楚起见,以前的代码是复制边缘列表,并将新边缘添加到副本中,而不是原始列表。

我可以看到的另一个内存管理问题是在构造函数中。 这是一个没有内存管理问题的音译。 还有其他方法可以在涉及较少代码的vector上使用 resize(...) 方法执行此操作(作为练习保留):

Graph(int numberOfNodes) {
    int i;
    for (i=0; i < numberOfNodes; ++i) {
        nodes.push_back(list<Edge>());
    }
}

还有其他一些我会做不同的事情,但你可能想把它带到 codereview.stackexchange.com 进行完整的审查。