我在c ++中编写了一个不起作用的简单算法。我发现当我从我自己制作的自定义类中排序指向对象的列表时,它们会发生变化。或者更准确地说,列表会更改为该类中的奇怪随机对象。
// ConsoleApplication45.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <map>
#include <list>
#include <math.h>
using namespace std;
class LocationNode;
class NodeMap;
class LocationNode
{
private:
char name;
int xLocation;
int yLocation;
//map<LocationNode*,int> neighbors;
LocationNode* neighbors[100];
int neighborWeight[100];
int neighborCount;
LocationNode *previous;
int score;
int CalcDistance(LocationNode &dest)
{
return (int)sqrt(pow(dest.xLocation-xLocation,2) + pow(dest.yLocation-yLocation,2));
}
public:
int finalScore;
bool operator<(LocationNode const& rhs) const
{
// Use whatever makes sense for your application.
return (finalScore < rhs.finalScore);
}
bool operator==(LocationNode const& rhs) const
{
// Use whatever makes sense for your application.
return (name == rhs.name && xLocation == rhs.xLocation && yLocation ==rhs.yLocation );
}
LocationNode(char name, int x, int y)
{
neighborCount = 0;
this->name = name;
this->xLocation = x;
this->yLocation = y;
}
string GetPath()
{
if(previous!=NULL)
{
return string(1, name).append((*previous).GetPath());
} else {
return string(1, name);
}
}
void Connect(LocationNode &other, int weight)
{
this->neighbors[neighborCount] = &other;
this->neighborWeight[neighborCount] = weight;
}
void CalcScore(LocationNode &previous, LocationNode &dest)
{
int index = 0;
for (int i = 0; i < neighborCount; i++)
{
if(neighbors[i] == &previous)
{
index = i;
}
}
score = previous.score + neighborCount[&index];
finalScore = previous.score + neighborCount[&index] + CalcDistance(dest);
}
void CalcNeighbors(LocationNode &dest)
{
for (int i = 0; i < neighborCount; i++)
{
(*neighbors[i]).CalcScore(*this,dest);
}
/*for (pair<LocationNode,int> node : neighbors)
{
node.first.CalcScore(*this,dest);
}*/
}
};
bool my_compare (LocationNode* a, LocationNode* b)
{
return a->finalScore < b->finalScore;
}
class NodeMap
{
private:
static LocationNode& str;
static LocationNode& dest;
static LocationNode* node;
static list<LocationNode*> nodes;
static void loop(bool isFirst)
{
if(isFirst)
{
node = &str;
}
(*node).CalcNeighbors(dest);
nodes.sort(my_compare);
node = nodes.front();
}
public:
static string start()
{
Init();
loop(true);
while(node != &dest)
{
loop(false);
}
return dest.GetPath();
}
static void Init()
{
nodes.clear();
LocationNode A ('A',1,2);
nodes.push_back(&A);
LocationNode B ('B',7,1);
nodes.push_back(&B);
LocationNode C ('C',2,8);
nodes.push_back(&C);
LocationNode D ('D',4,3);
nodes.push_back(&D);
LocationNode E ('E',9,6);
nodes.push_back(&E);
LocationNode F ('F',1,2);
nodes.push_back(&F);
A.Connect(B,2);
B.Connect(D,3);
D.Connect(E,2);
E.Connect(F,3);
A.Connect(C,1);
C.Connect(F,10);
dest = F;
str = A;
}
};
LocationNode& NodeMap::str = *(new LocationNode('A',1,2));
LocationNode& NodeMap::dest = *(new LocationNode('F',1,2));
LocationNode* NodeMap::node = &str;
list<LocationNode*> NodeMap::nodes;
int _tmain(int argc, _TCHAR* argv[])
{
cout << &(NodeMap::start());
cin.get();
return 0;
}
排序之前https://i.imgur.com/nqU4m0j.png
排序后https://i.imgur.com/eo2U3EB.png
很抱歉,我无法直接在这里发布图片,但我没有足够的声誉。
答案 0 :(得分:6)
您正在推送指向堆栈分配对象的指针。在这些对象超出范围之后,这些指针变得无效,因此您的nodes
容器最终会出现一堆悬空指针。您应该使用指向堆分配对象的指针填充此容器,以使它们有效。并且不要忘记稍后删除它们或使用智能指针。或者,您可以按值存储列表中的对象。请注意,与std::vector
不同,std::list
在添加或删除新项目时不会使指向现有项目的指针无效。
list<LocationNode> nodes;
nodes.emplace_back('A', 1, 2);
答案 1 :(得分:3)
像
这样的行LocationNode A = *(new LocationNode('A',1,2));
在堆栈上创建类型为LocationNode
的对象。新操作在堆上创建一个新对象,该对象将复制到本地对象中(请参阅A
,B
,...),然后泄露。
当您向nodes
conatiner添加本地对象时,只要退出Init
函数,nodes
中包含的数据就会因任何目的而无法使用。
更改上面的行:
LocationNode* A = new LocationNode('A',1,2);
然后使用
将它们添加到列表中nodes.push_back(A);
应该摆脱90%的问题。
答案 2 :(得分:2)
LocationNode A = *(new LocationNode('A',1,2));
nodes.push_back(&A);
你在这做什么?您在堆上创建了对象new LocationNode('A',1,2)
,然后将此对象的副本设为LocationNode A = *(new LocationNode('A',1,2));
,A
为副本,并在init
函数中创建为本地变量。您将局部变量对象的地址推送到nodes
向量,但是当init
函数结束时,所有本地对象都被删除,并且您有nodes
悬挂指针 - 它们指向不具有的对象存在。
您可以更改为
LocationNode* A = new LocationNode('A',1,2);
nodes.push_back(A);
并记住删除所有动态分配的对象。