《游戏编程入门》源代码子画面销毁bug与vector容器vector::erase的问题

原书中GameEngine的代码有两处bug,源代码分别为:

void GameEngine::CleanupSprites()
{
  // Delete and remove the sprites in the sprite vector
  vector<Sprite*>::iterator siSprite;
  for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  {
    delete (*siSprite);
    m_vSprites.erase(siSprite);
    siSprite--;
  }
}
void GameEngine::UpdateSprites()
{
  // Check to see if the sprite vector needs to grow
  if (m_vSprites.size() >= (m_vSprites.capacity() / 2))
    m_vSprites.reserve(m_vSprites.capacity() * 2);

  // Update the sprites in the sprite vector
  RECT          rcOldSpritePos;
  SPRITEACTION  saSpriteAction;
  vector<Sprite*>::iterator siSprite;
  for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  {
    // Save the old sprite position in case we need to restore it
    rcOldSpritePos = (*siSprite)->GetPosition();

    // Update the sprite
    saSpriteAction = (*siSprite)->Update();

    // Handle the SA_KILL sprite action
    if (saSpriteAction & SA_KILL)
    {
		
      // Notify the game that the sprite is dying
      SpriteDying(*siSprite);

      delete (*siSprite);
      m_vSprites.erase(siSprite);
      siSprite--;
      continue;
    }

    // See if the sprite collided with any others
    if (CheckSpriteCollision(*siSprite))
      // Restore the old sprite position
      (*siSprite)->SetPosition(rcOldSpritePos);
  }
}

这两段代码在VC6编译器能正常运行,但在VS2008以后的编译器编译之后运行时产生错误,分别修正如下:

void GameEngine::CleanupSprites()
{
  // Delete and remove the sprites in the sprite vector
  vector<Sprite*>::iterator siSprite;
  for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  {
    delete (*siSprite);//注意这里
  }
  m_vSprites.clear();//注意这里
}
//=================================================
//或
void GameEngine::CleanupSprites()
{
 // Delete and remove the sprites in the sprite vector
 vector<Sprite*>::iterator siSprite;
 for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();)//注意这里
 {
  delete (*siSprite);
  siSprite = m_vSprites.erase(siSprite); //注意这里
 }
}
//=====================================================

void GameEngine::UpdateSprites()
{
	// Check to see if the sprite vector needs to grow
	if (m_vSprites.size() >= (m_vSprites.capacity() / 2))
	{
		m_vSprites.reserve(m_vSprites.capacity() * 2);
	}
	// Update the sprites in the sprite vector
	RECT          rcOldSpritePos;
	SPRITEACTION  saSpriteAction;

	vector<Sprite*>::iterator siSprite;
	for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();)//注意这里
	{
		// Save the old sprite position in case we need to restore it
		rcOldSpritePos = (*siSprite)->GetPosition();

		// Update the sprite
		saSpriteAction = (*siSprite)->Update();

		// Handle the SA_KILL sprite action
		if (saSpriteAction & SA_KILL)
		{

			// Notify the game that the sprite is dying
			SpriteDying(*siSprite);
			delete (*siSprite);
			//siSprite--;
			siSprite = m_vSprites.erase(siSprite);	//注意这里
			continue;
		}

		// See if the sprite collided with any others
		if (CheckSpriteCollision(*siSprite))
		{
			// Restore the old sprite position
			(*siSprite)->SetPosition(rcOldSpritePos);
		}
		siSprite++;//注意这里
	}

}

分析:vector.erase(p)之后,所有指向p所指的内存的迭代器全部失效,但是它的返回值是指向下一个元素的迭代器。以前的编译器之所以能够成功运行,应该是之前的标准并不清晰或者编译器内部实现的问题,VS2008之后严格按照标准来之后就出现运行时错误。


PS :

 《BEGINNING GAME PROGRAMMING》 中还有个问题:程序要是换用了修改了BMP图像资源,结果是图像不能正常显示变黑的了。 

http://blog.csdn.net/dkink/article/details/2310564  给出了解决办法,但还有点小问题,下面给出原因和改正办法。

这里作者忽略了一个小小的问题,...........无压缩BMP文件的
pBitmapInfo->bmiHeader.biSizeImage 里面的值不一定是图像的真实大小,可能是0或者随意的值。 所以需要重新计算,在Bitmap.cpp里面,Bitmap类的 两个Create函数的下面这个位置添加计算biSizeImage的代码。

// Store the width and height of the bitmap
  BITMAPINFO* pBitmapInfo = (BITMAPINFO*)pBitmapImage;
  m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
  m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;

// 计算biSizeImage填充回去,是增加的代码 

//注意这里
int lineByte=(m_iWidth*pBitmapInfo->bmiHeader.biBitCount/8+3)/4*4; //位图每行占多少个字节
pBitmapInfo->bmiHeader.biSizeImage = m_iHeight*lineByte;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


  // Get a handle to the bitmap and copy the image bits
  PBYTE pBitmapBits;
  m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
    (PVOID*)&pBitmapBits, NULL, 0);

参考资料:

1.C++Primer中文版(第四版)P282~283




2.http://www.cplusplus.com/forum/beginner/47420/

3.http://blog.csdn.net/dkink/article/details/2330905

4.http://blog.csdn.net/vhshiwen/article/details/4808867

5.http://www.cnblogs.com/buxianghe/archive/2012/06/25/2560713.html

你可能感兴趣的:(《游戏编程入门》源代码子画面销毁bug与vector容器vector::erase的问题)