Class Pointers vs Reference

时间:2013-10-14 23:55:23

标签: c++ code-structure memory

我理解指针和引用的基础知识,但我最大的问题是决定何时应该使用它们(以及哪些)。我将给出的主要例子是一个基本游戏。假设设置类似于:

  • 新世界
    • 摄像机
    • 地图

世界是一个指针,因为每次游戏开始新的保存或加载现有的保存时,它都会删除世界并加载一个新的。但在世界范围内,只有一个存在的相机和地图应该存在,并且只存在于世界的持续时间。如果世界被摧毁,那么显然他们应该也是如此。但是..让我们说Map需要访问相机(但其他对象也是如此),Camera应该通过引用传递给Map还是作为指针,或者?例如,如果它应该通过引用,它应该是:

map = Map(&camera);
(inside map class) Map(Camera camera) {...}

或更像是:

map = Map(camera);
(inside map class) Map(Camera &camera) {...}

另外,假设Map包含一个称为网格的2D矢量图块。类似的东西:

std::vector< std::vector< Tile > > > grid;

现在假设我有一个需要传入网格的PathFinder类。它需要直接编辑切片以更改f,g等值(用于路径查找)。这个2D矢量应该只是Tile的普通2D矢量吗?整个事物都是通过引用路径查找器传递的?或者它应该是Tile指针的2D向量?

此外,NPC和玩家将拥有currentTile,这是他们目前正在使用的牌。他们需要有一个参考或指向该图块的指针,这样他们也可以通过NPC / Player类中的类似内容将自己设置为该图块上的占用者:

currentTile = tile;
currentTile->SetOccupant(this);

当我然后销毁该网格以加载新地图时,另一个问题就出现了,我如何轻松处理以确保没有任何东西指向不再存在的Tiles。我是否只需循环遍历这些类并将currentTile设置为NULL?

这是我开始真的被这些东西搞糊涂的地方。 任何帮助都表示赞赏,因为我显然很漂亮。 @ _ @; 如果这不是游戏主题相关,那就很抱歉。如果它需要移动到不同的stackexchange,请告诉我或移动它(如果可以的话)。 &GT; _&LT;

1 个答案:

答案 0 :(得分:1)

考虑Map类。您可以通过引用或作为指针传入相机。这真的不重要。重要的是相机传入后会发生什么。你打算将它分配给一个Camera *吗?否则,在构造函数中设置Camera将无法实现。每次调用需要摄像头的Map时,你都必须提供一个Camera指针/参考。

对于存储Tile对象,单个维度std :: vector&lt;&gt;会做得很好。通过使用一些简单的数学运算,可以非常轻松地遍历此平铺网格。在内部嵌套另一个向量只会导致不必要的开销。以下是执行此操作的示例算法:

std::vector<Tile> tiles = makeTiles();
for (int y=0; y<mapHeight; y++)
{
   for (int x=0; x<mapWidth; x++)
   {
      Tile tile = tiles.at(x + y*mapWidth);
      tile.doSomethingWithTile();
   }
}

决定如何将地图数据从地图获取到路径查找器,这实际上取决于您希望如何保护地图数据。通过提供对所有磁贴数据的引用,您实际上是将其公开访问。由于PathFinder需要编辑单个图块而不是整个图块阵列本身,更好的方法是使用这样的方法:

Tile* Map::AccessTile(int tx, int ty);

这样,tile数据的整个向量都不会公开,但是PathFinder将能够获得它所需要的内容。另外,Map :: AccessTile()可以是私有的,并且PathFinder被声明为Map的朋友。另一种方法是提供Map :: SetTileF(int tx,int ty,float f)等方法。但这可能很乏味。

对于NPC和播放器,可以使用类似的解决方案。它们实际上不需要对它们所在的磁贴具有直接写入权限。添加一个方法,如Map :: SetTileOccupant(Entity * entity)和相应的Map :: GetTileOccupant()。

现在您关注删除对象了。您应该看一下C ++提供的一些模拟指针(特别是std::shared_ptr<>std::weak_ptr<>)。对这些的快速解释是shared_ptr是一个“拥有”一个对象的指针,一个weak_ptr知道访问该对象的位置,但实际上并不“拥有”该对象。

使用这些模拟指针,您可以执行以下操作:

//prototype for setWorld
//note that shared_ptr<> casts to weak_ptr<> nicely
Camera::setWorld(std::weak_ptr<World> world);

//setup the camera and world
std::shared_ptr<World> world(new World);
Camera camera;
camera.setWorld(world);

使用上面的代码,相机有一个指向世界的指针。如果由于某种原因删除了世界,相机可以通过以下方法解决这个问题:

bool Camera::worldIsValid()
{
   return (this->mWorld.expired() == false);
}

此外,您将相机封装在一个世界中,这可能是您不需要做的事情。相反,Camera可以是独立的,只要它需要有关它的信息或世界中包含的地图,就可以引用它。