如果要阅读的代码太多,我深表歉意,如果我可以通过解释简化,请告诉我,如果您想对我的设计/实践发表评论,请随时联系我。
所以我的播放器被删除了两次,我不确定为什么。如果查看调用堆栈,您会发现 GameEventManager 实际上在调用 GameState 析构函数之前调用 Player 析构函数,即使 GameState 是具有指向 Player 的指针的那个。我在想这可能是因为它也首先破坏了 vector ,所以它在 vector 中找到玩家并试图破坏它。我不知道为什么它会尝试破坏 Player,因为仍然有一个 GameState 对象知道的对 Player 的引用。共享指针功能应防止 Player 被破坏。
也许我的做法是错误的,如果可以的话,有人可以在这里为我指出正确的最佳实践方向吗?谢谢
调用堆栈:
游戏状态.h
#ifndef _level
#define _level
#include <vector>
#include "Player.h"
#include <memory>
using namespace std;
class GameState // A representation of the Level/Game/Scene
{
public:
GameState();
virtual ~GameState() {}
//Keep track of the game's state
//Maybe get rid of the Level class, and make this a class, and move the Level functionality here?
static void EndGame(const bool & b) { mbEndGame = b; }
static const bool & EndGame() { return mbEndGame; }
private:
void SetPlayer(shared_ptr<Player> sptrPlayer) { msptrPlayer = sptrPlayer; }
static bool mbEndGame;
shared_ptr<Player> msptrPlayer;
vector<shared_ptr<Player>> msptrMob; // Representation of all the NPCs in the game. Eventually make a Mob class but for now just use Player
// shared_ptr<LevelMap> mMap // Representation of what the game looks like visually
// Renderer // Should the level have the renderer to create the graphics? Or should this be handled by another "GUI Layer" and interact with this layer as little as possible ?
};
#endif
游戏状态.cpp
#include "stdafx.h"
#include "GameState.h"
bool GameState::mbEndGame(false);
GameState::GameState() : msptrPlayer(NULL)
{
shared_ptr<Player> sptrPlayer(new Player);
SetPlayer(sptrPlayer);
}
GameObject.h
#ifndef _game_object
#define _game_object
#include <memory>
// Game Object Classes inherit this so they are registered with GameEventManager.
using namespace std;
class GameObject{
public:
GameObject();
virtual ~GameObject() {}
virtual void Update() = 0;
virtual void Start() = 0;
};
#endif
GameObject.cpp
#include "stdafx.h"
#include "GameObject.h"
#include "GameEventManager.h"
GameObject::GameObject()
{
shared_ptr<GameObject> ptr(this);
GameEventManager::GetGameEventManager()->RegisterGameObject(ptr);
}
播放器.h
#ifndef _player
#define _player
#include "GameObject.h"
//A representation of the Player. Used by Level.
class Player : public GameObject
{
public:
Player();
virtual ~Player() {}
private:
virtual void Update();
virtual void Start();
int miMaxHealth;
};
#endif
播放器.cpp
#include "stdafx.h"
#include "Player.h"
#include "GameState.h"
Player::Player() : miMaxHealth(100) {};
void
Player::Start()
{
}
void
Player::Update() // reimplement GameObject::Update(), which is called by the GameEventManager
{
--miMaxHealth;
if (miMaxHealth <= 0)
{
GameState::EndGame(true);
}
}
游戏事件管理器.h
#ifndef _game_event_manager
#define _game_event_manager
#include "stdafx.h"
#include <memory>
#include <vector>
#include "GameObject.h"
#include "GameState.h"
using namespace std;
class GameEventManager{
//Object which inherit from GameObject are automatically registered with GameEventManager when they are constructed.
// GameEventManager creates the level object to represent the game, and then runs Start() on all registered GameObjects
// and then continually runs Update() on all registered game objects until the GameState is set to EndGame.
public:
virtual ~GameEventManager(){} // This gets called at the end of the program (I guess whne static variables are destroyed), and crashes during vector<shared pointer <GameObject>> destruction, probably because
// Player already destroyed it. So... not sure what to do. If I make it non-static
void StartGameEvents();
const static shared_ptr<GameEventManager>& GetGameEventManager();
const shared_ptr<GameState>& GetLevel();
void RegisterGameObject(shared_ptr<GameObject> sptrGameObject);
const shared_ptr<vector<shared_ptr<GameObject>>>& GetRegisteredGameVector() const { return mvecRegisteredGameVector; }
private:
GameEventManager(); //singleton
void AddGameObject(shared_ptr<GameObject>);
shared_ptr<GameState> mLevel;
shared_ptr<vector<shared_ptr<GameObject>>> mvecRegisteredGameVector; //Reference because shared pointer will double delete otherwise. ~Level() still deletes it but this way I guess it doesn't try to delete again? but...
//Now I'm trying it as a shared_ptr, but it's not working. ~Level() still deletes it even though there is a shared pointer to a vector pointing to the Player. Why is ~Level() doing this?
static shared_ptr<GameEventManager> msptrGameEventManager;
};
#endif
游戏事件管理器.cpp
#include "stdafx.h"
#include "GameEventManager.h"
#include "GameState.h"
shared_ptr<GameEventManager> GameEventManager::msptrGameEventManager(new GameEventManager);
void
GameEventManager::StartGameEvents()
{
//run once
int size = GetRegisteredGameVector()->size();
vector<shared_ptr<GameObject>> & vecsptrRegisteredGameVector = (*GetRegisteredGameVector());
for (int i = 0; i < GetRegisteredGameVector()->size(); ++i)
{
vecsptrRegisteredGameVector[i]->Start(); //nothing for now
}
//keep running
while (GetLevel()->EndGame() != true)
{
for (int i = 0; i < GetRegisteredGameVector()->size(); i++)
{
(*GetRegisteredGameVector())[i]->Update(); //Player's life goes from 100 to zero, see Player::Update
}
}
return;
// GameState destructor is called and destroys player for some reason, even though it's still being referenced by the GameEventManager's vector.
}
GameEventManager::GameEventManager() : mvecRegisteredGameVector(new vector<shared_ptr<GameObject>>) , mLevel(NULL) //Instantiating the level before the GameEventManager is fully instantiated causes an infinite recursion.
{
return;
}
const shared_ptr<GameEventManager>&
GameEventManager::GetGameEventManager()
{
if (!msptrGameEventManager)
{
msptrGameEventManager.reset(new GameEventManager);
}
return msptrGameEventManager;
}
const shared_ptr<GameState>&
GameEventManager::GetLevel()
{
if (!mLevel)
{
mLevel.reset(new GameState);
}
return mLevel;
}
void
GameEventManager::RegisterGameObject(shared_ptr<GameObject> sptrGameObject)
{
GetGameEventManager()->AddGameObject(sptrGameObject);
}
void
GameEventManager::AddGameObject(shared_ptr<GameObject> sptrGameObject)
{
GetRegisteredGameVector()->push_back(sptrGameObject);
}
最佳答案
GameObject::GameObject()
{
shared_ptr<GameObject> ptr(this);
GameEventManager::GetGameEventManager()->RegisterGameObject(ptr);
}
ptr
在此功能中不与任何其他人共享所有权shared_ptr
独立构建,就像在 shared_ptr<Player> sptrPlayer(new Player);
声明的那样.创建两个 shared_ptr
来自原始指针,而不是复制第一个指针,通常会导致双重删除。
相反,您可以这样做:
class GameObject :
public std::enable_shared_from_this<GameObject>
{
protected:
GameObject(); // creates the original shared_ptr
virtual ~GameObject();
};
class Player : public GameObject
{
public:
static std::shared_ptr<Player> create();
private:
Player() : GameObject() {}
virtual ~Player() {}
};
std::shared_ptr<Player> Player::create() {
return dynamic_pointer_cast<Player>((new Player)->shared_from_this());
}
关于c++ - 使用共享指针双重删除,即使对象仍然有一个 shared_ptr,它的析构函数正在被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24977582/