C++ 结构列表的分配向量
我有一个类,它有一个成员,它是结构列表的向量,我想动态分配列表和列表中的元素。我不知道为什么,但出于某种原因,我的列表似乎是空的,即使我正在添加元素 代码如下:C++ 结构列表的分配向量,c++,list,memory-management,vector,C++,List,Memory Management,Vector,我有一个类,它有一个成员,它是结构列表的向量,我想动态分配列表和列表中的元素。我不知道为什么,但出于某种原因,我的列表似乎是空的,即使我正在添加元素 代码如下: #include <iostream> #include <vector> #include <list> using namespace std; template <class Weight> class Graph { private: struct Edge {
#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();
}
好像名单是空的。尝试使用已调试的查找错误,但运气不佳。我来自ANSI C的背景,我仍然不确定新关键字是如何工作的。我应该在向量中存储指向列表的指针吗?我应该在列表中存储指向结构的指针吗
另外,如果答案也能提供如何释放类析构函数上的内存,我将非常感激
注意:模板是这样的,我的图上的权重可以定义为int或float
编辑:我只想补充一点,我以前没有使用任何硬编码指针。您在这里看到的代码是我经过几个小时的反复尝试后得到的,以使其正常工作。如评论中所述,这里的内存管理存在许多问题,但边缘列表保持为空的原因是
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
上的方法还有其他一些方法可以实现这一点,这些方法涉及的代码较少(留作练习):
图形(int numberOfNodes){
int i;
对于(i=0;i
我还可以做一些其他的事情,但您可能希望将此内容带到codereview.stackexchange.com进行完整的审阅
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
}
}
这将修复您的输出
您也在操作列表的副本,而不是实际列表:
list<Edge> edgesA= nodes.at(nodeA);
list edgesA=nodes.at(nodeA);
您应将其声明为:
list<Edge>& edgesA= nodes.at(nodeA);
// ^^ This makes it a reference instead of a copy
list&edgesA=nodes.at(nodeA);
//^^这使其成为参考,而不是副本
这段代码中有很多内存管理问题。首先,您的图
构造函数中存在内存泄漏。没有理由使用您编写的代码在堆上分配列表
(或边缘
)实例。我做了更改,但它仍然没有打印任何内容。我知道内存泄漏,实际上我是按照您描述的那样做的(没有使用原始指针),但它不工作。是的,现在它工作了,谢谢。我习惯于Java,在Java中,所有不是原语的东西都是引用。我知道如何在函数声明中使用&作为“通过引用传递”,或者从值中获取指针(例如int j=5;int*I=&j;),但我从未在声明中见过它;在GeneratorDomainGraph中,我是否也应该在此处使用引用?Graph对象在堆栈中分配,然后我将其返回给main函数。GeneratorDomainGraph中的Graph对象是否被复制到main中的Graph对象中(这是一种巨大的资源浪费,因为该图形可能是巨大的)?在这种情况下,我是否应该使用new关键字在堆中分配图形?您不会(实际上也不能)从generateRandomGraph
函数返回引用。您正在返回一个副本(很可能会被省略),该副本将存储在main
中的g
变量中。因此,避免重复的正确方法是将我的函数设置为:void generateRandomGraph(Graph&g,int numberOfNodes),接受对图形对象的引用并对其进行修改,对吗?
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);
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