SDL析构函数调用太早
SDL Destructor Called too early
我正在SDL中编程一个基于瓦片的映射,Map
类的构造函数用于设置用于表示其中包含的每个MapCell
对象的映像。但是,我的Sprite
类的析构函数有问题,该析构函数用于释放对象所持有的SDL_Surface*
。析构函数被提前调用,我不完全确定为什么。这里是我的Map
构造函数的精简版本,只是显示了如何分配单元格的精灵。
Map::Map(string fileName, int tileWidth, int tileHeight)
{
string mapData = ReadMap(fileName);
_cells = new MapCell[_width*_height];
for(int y = 0; y < _height; y++)
{
for(int x = 0; x < _width; x++)
{
int currentCell = y*_width+x;
if(mapData[currentCell] == '0' || mapData[currentCell] == 'P' || mapData[currentCell] == 'X')
{
_cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Grass.bmp");
if(mapData[currentCell] == 'P')
_cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Player.bmp");
if (mapData[currentCell] == 'X')
_cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Target.bmp");
}
else if(mapData[currentCell] == '1')
_cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Wall.bmp");
}
}
}
析构函数似乎是在创建Sprite对象后立即调用的。我在这里错过了什么?我也尝试过在堆上分配MapCell
的_sprite
成员,但这会导致同样的问题。据我所知,它并没有超出范围,因为创建的Sprite
对象是Map
对象的一部分。
以下是我的Sprite
类的构造函数和析构函数:
Sprite::Sprite(void)
{
_texture = NULL;
_position = Point2D::Zero();
}
Sprite::Sprite(Point2D position, std::string texPath)
{
_texture = Content::LoadBMP(texPath);
_position = position;
}
Sprite::~Sprite(void)
{
SDL_FreeSurface(_texture);
}
如果有帮助的话,这是我的主菜单:
int main( int argc, char* args[] )
{
const int TILEWIDTH = 32;
const int TILEHEIGHT = 32;
// Initialization
InitSDL();
Map map = Map("Assets/Maps/Map3.txt", TILEWIDTH, TILEHEIGHT);
Window::SetSize(Rectangle(0, 0, map.GetWidth()*TILEWIDTH, map.GetHeight()*TILEHEIGHT));
PathFinder pathFinder = PathFinder();
List<Point2D> path = pathFinder.FindPath(map, map.GetPlayerStart(), map.GetTarget());
List<Sprite> PathNodes = List<Sprite>();
for(int i = 0; i < path.GetCount(); i++)
PathNodes.Add(Sprite(*path(i)*32, "Assets/Graphics/PathNode.bmp"));
bool quit = false;
SDL_Event Event;
while(quit == false)
{
while(SDL_PollEvent(&Event))
{
if(Event.type == SDL_QUIT)
quit = true;
}
map.Draw();
for(int i = 0; i < path.GetCount(); i++)
{
if(PathNodes(i)->GetPosition() != map.GetPlayerStart()*32 && PathNodes(i)->GetPosition() != map.GetTarget()*32)
PathNodes(i)->Blit();
}
Window::Flip();
}
//Quit SDL
SDL_Quit();
return 0;
}
问题是分配x._sprite = Sprite(...)
。这将创建一个Sprite
临时文件,将其字段复制到_sprite
中,然后销毁该临时文件。此外,在执行赋值之前,它确实而不是调用_sprite
上的析构函数,所以旧的_texture
只会泄漏。
如果您想避免这种情况,请在Sprite
上使用.set
或.load
函数来更新Sprite
的内容,而不是复制,并创建私有赋值和复制构造函数方法,以避免意外滥用。
for(int i = 0; i < path.GetCount(); i++)
PathNodes.Add(Sprite(*path(i)*32, "Assets/Graphics/PathNode.bmp"));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// a temporary here!
当该表达式结束时,将调用临时Sprite
的析构函数,释放曲面,并为PathNodes
对象留下一个指向已释放曲面的悬空指针。您的代码中可能有更多这样的表达式。
遵循三条规则,为Sprite
类编写一个合适的复制构造函数和赋值运算符。
请参阅SDL_Surface
的文档以了解需要执行的操作(您可能需要手动增加曲面的refcount
成员(。
相关文章:
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 变量没有改变?通过向量的函数调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 模板函数调用
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 析构函数调用
- 成员函数调用和C++对象模型
- 使用共享指针的函数调用,其对象应为 const
- 函数调用C++中的参数太少
- 函数调用的参数太多,预期为 0,有 1。 "InfInt.h"字符串函数
- 函数调用运算符重载的参数太多
- C++ 析构函数调用得太早了
- 使用 range-for 循环:函数调用的参数太少,未指定单个参数'a'
- c++:函数调用中参数太少
- IntelliSense:函数调用中的参数太少
- SDL析构函数调用太早
- 在销毁期间使用std::shared_ptr发生段故障,可能是由于堆栈上的函数调用太多