gpt4 book ai didi

c++ - 使用共享指针双重删除,即使对象仍然有一个 shared_ptr,它的析构函数正在被调用

转载 作者:太空狗 更新时间:2023-10-29 23:33:00 25 4
gpt4 key购买 nike

如果要阅读的代码太多,我深表歉意,如果我可以通过解释简化,请告诉我,如果您想对我的设计/实践发表评论,请随时联系我。

所以我的播放器被删除了两次,我不确定为什么。如果查看调用堆栈,您会发现 GameEventManager 实际上在调用 GameState 析构函数之前调用 Player 析构函数,即使 GameState 是具有指向 Player 的指针的那个。我在想这可能是因为它也首先破坏了 vector ,所以它在 vector 中找到玩家并试图破坏它。我不知道为什么它会尝试破坏 Player,因为仍然有一个 GameState 对象知道的对 Player 的引用。共享指针功能应防止 Player 被破坏。

也许我的做法是错误的,如果可以的话,有人可以在这里为我指出正确的最佳实践方向吗?谢谢

调用堆栈:

enter image description here enter image description here enter image description here游戏状态.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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com