我遇到的问题与创建对象副本有关。我有一个map类,它包含一个std :: map,其中包含一组定义由其ID索引的不同tile类型的类,以及一个向量中的一堆tile,每个tile都有一个指向其中一个类的指针。另外,我还有另一个包含地图的类Scenario。
当我创建一个Scenario对象并尝试对其地图执行任何操作时,问题就出现了。复制指针时一定有问题,但我无法弄明白。
我试图将代码减少到重现问题的必要条件:
#include <string>
#include <map>
#include <vector>
#include <iostream>
using namespace std;
class TileInfo {
string name;
public:
int id;
TileInfo() {};
TileInfo(int id, string name);
string getName() const;
};
TileInfo::TileInfo(int id, string name)
{
this->id = id;
this->name = name;
}
string TileInfo::getName() const
{
return name;
}
class Tile
{
public:
TileInfo* info;
Tile() {};
Tile(const Tile & other, map<int,TileInfo> & info);
Tile (TileInfo* info);
string getName() const;
};
Tile::Tile (TileInfo* tileInfo)
{
this->info = tileInfo;
}
Tile::Tile( const Tile & other, map<int,TileInfo> & tileInfo )
{
map<int,TileInfo>::iterator it = tileInfo.find(other.info->id);
if(it == tileInfo.end())
this->info = NULL;
else
this->info = &(it->second);
}
string Tile::getName() const
{
return info->getName();
}
class Map
{
vector <vector <Tile>> tiles;
map <int, TileInfo> tileInfo;
public:
void print() const;
Map() {};
Map(map<int,TileInfo> tileInfo);
Map(const Map & other);
string getName() const;
void loadTiles();
};
Map::Map(map<int,TileInfo> tileInfo)
{
this->tileInfo = tileInfo;
}
Map::Map(const Map & other)
{
this->tileInfo = other.tileInfo;
for(unsigned int i = 0; i < other.tiles.size(); i++)
{
vector<Tile> line;
for(unsigned int j = 0; j < other.tiles[i].size(); j++)
{
Tile tmpTile = Tile(other.tiles[i][j],tileInfo);
line.push_back(tmpTile);
}
this->tiles.push_back(line);
}
}
void Map::print() const
{
for(unsigned int i = 0; i < tiles.size(); i++)
{
for(unsigned int j = 0; j < tiles[i].size(); j++)
{
cout << "Tile at " << i << ", " << j << " is a "; cout << tiles[i][j].getName() << endl;
}
}
}
void Map::loadTiles()
{
for(unsigned int i = 0; i < 3; i++)
{
vector <Tile> line;
for(unsigned int j = 0; j < 3; j++)
{
map<int,TileInfo>::iterator ite = tileInfo.find(i);
if( ite!=tileInfo.end())
line.push_back(Tile(&(ite->second)));
else
{
line.push_back(Tile(NULL));
}
}
tiles.push_back(line);
}
}
class Scenario
{
public:
Map map;
Scenario() {};
Scenario(Map map);
};
Scenario::Scenario(Map map)
{
this->map = map;
this->map.print();
}
Map createMap()
{
map<int,TileInfo> tmpInfo;
for(unsigned int i = 0; i < 3; i++)
{
tmpInfo.insert(pair<int,TileInfo>(i,TileInfo(i,"testname")));
}
Map rtrnVal = Map(tmpInfo);
rtrnVal.loadTiles();
return rtrnVal;
}
int main()
{
Map newMap = createMap();
Scenario newScenario = Scenario(newMap);
newScenario.map.print();
int input;
cin >> input;
}
Scenario构造函数末尾的print()正确打印地图的内容,但是在分配方案后的那个会导致崩溃。任何帮助将不胜感激。
答案 0 :(得分:2)
您正在存储指向TileInfo
:
class Tile
{
public:
TileInfo* info;
...
但是一旦复制了对象,指针就会被复制,但是它们指向的TileInfo
已被破坏,所以它们引用了无效的内存=崩溃。
考虑实现复制构造函数/复制操作符来处理它。
答案 1 :(得分:2)
存储原始TileInfo
对象的原始std :: map位于:
map<int,TileInfo> tmpInfo;
for(unsigned int i = 0; i < 3; i++)
{
tmpInfo.insert(pair<int,TileInfo>(i,TileInfo(i,"testname")));
}
这是房子对的地图。然后你复制一下所说的地图。它会创建所有TileInfo
个对象的副本,这没关系。
Map rtrnVal = Map(tmpInfo);
但这是车轮开始脱落的地方。您在此处触发loadTiles
,这会设置您的地图,这些地图会在TileInfo
中添加相对rtrnVal
个对象。这段代码:
rtrnVal.loadTiles();
导致此代码。请注意,您将映射的TileInfo
对象的地址推送到向量中。这些驻留的地图是此对象地图。
void Map::loadTiles()
{
for(unsigned int i = 0; i < 3; i++)
{
vector <Tile> line;
for(unsigned int j = 0; j < 3; j++)
{
map<int,TileInfo>::iterator ite = tileInfo.find(i);
if( ite!=tileInfo.end())
line.push_back(Tile(&(ite->second)));
else
{
line.push_back(Tile(NULL));
}
}
tiles.push_back(line);
}
}
最后,回到我们开始的地方你做到了:
return rtrnVal;
这会制作Map
的副本,该副本会制作向量地图的副本,其中包含指向TileInfo
内地图中rtrnVal
的指针即将在函数退出时销毁。结果回到了呼叫方。
Map newMap = createMap();
newMap
现在暂挂指向TileInfo
rtrnVal
createMap
内TileInfo
个对象的悬挂指针。
可能的解决方案
不要使用包含指向TileInfo
的指针的向量映射,而是考虑索引的向量映射,其中每个索引键入{{1}中基于0的插槽地图旁边包含的std::vector
。我可以看到你想要做什么(单个TileInfo
在多个单元格中共享),所以你仍然可以获得这些好处。无论地图在哪里(它们都由相同的Map
对象拥有),向量都会出现,并且复制不会对任何东西造成伤害,因为地图(索引)和向量({{1} }}将安全复制。最后你仍然得到你想要的东西(单数TileInfo
s)但现在用数字而不是指针索引。作为奖励,您不必在自定义副本中处理从一个映射到另一个映射的指向TileInfo的指针。它的所有相对(0 .. n-1)
祝你好运。