C++98转C++17:std::vector原始指针改智能指针选型咨询
C++17游戏状态机智能指针改造方案
一、智能指针适用场景
- std::unique_ptr:优先选用。游戏状态机的状态栈是状态对象的唯一所有者,每个状态只会存在于栈中,不会被其他模块共享。unique_ptr独占所有权,零额外开销,完全匹配状态机的内存管理需求,能自动在状态被移除时销毁对象,彻底避免内存泄漏。
- std::shared_ptr:仅当你的状态需要被状态机之外的其他对象共享持有(比如某个状态同时被UI系统、剧情模块引用)时才考虑使用。但游戏状态机里这种场景极少,shared_ptr的引用计数会带来额外性能开销,非必要别用。
二、具体改造方案
1. 核心修改点
- 把状态机的容器从
std::vector<GameState*>改成std::vector<std::unique_ptr<GameState>> - 利用unique_ptr的移动语义传递所有权,避免原始指针暴露
- 修正原代码中的逻辑错误(比如
pushState里误用pop_back、changeState未添加新状态)
2. 完整改造后代码
#include <vector> #include <memory> #include <string> class GameState { public: virtual ~GameState() = default; // 显式声明虚析构,确保子类正确销毁 virtual bool onEnter() = 0; virtual bool onExit() = 0; virtual std::string getStateID() const = 0; }; class MenuState : public GameState // 修正继承权限为public,否则外部无法多态调用 { public: MenuState() = default; ~MenuState() override = default; bool onEnter() override { return true; } // 补充实现,避免编译错误 bool onExit() override { return true; } std::string getStateID() const override { return s_menuId; } private: static const std::string s_menuId; }; const std::string MenuState::s_menuId = "MENU"; // 静态成员定义 class StateMachine { public: // 接受unique_ptr,转移所有权到状态栈 void pushState(std::unique_ptr<GameState> pState) { m_gameStates.push_back(std::move(pState)); m_gameStates.back()->onEnter(); } // 替换顶部状态:先销毁旧状态(如果onExit成功),再加入新状态 void changeState(std::unique_ptr<GameState> pState) { if (!m_gameStates.empty()) { if (m_gameStates.back()->onExit()) { // unique_ptr会自动销毁对象,无需手动delete m_gameStates.pop_back(); } } pushState(std::move(pState)); } // 可选:弹出顶部状态 void popState() { if (!m_gameStates.empty()) { if (m_gameStates.back()->onExit()) { m_gameStates.pop_back(); } } } private: std::vector<std::unique_ptr<GameState>> m_gameStates; }; int main(int argc, char** argv) { StateMachine sm; // 直接在pushState中构造对象,无需手动new/delete sm.pushState(std::make_unique<MenuState>()); // 切换到其他状态示例(假设有PlayState) // sm.changeState(std::make_unique<PlayState>()); }
3. 关键细节说明
- 虚析构函数:GameState必须声明虚析构,否则子类对象通过基类指针销毁时会有未定义行为,C++17中可以用
= default简化写法 - 移动语义:
std::move(pState)把unique_ptr的所有权转移给容器,避免拷贝(unique_ptr不可拷贝) - make_unique:C++14引入的安全创建unique_ptr的方法,避免裸new,比直接构造更安全
- 权限修正:原代码中MenuState私有继承GameState,会导致多态调用失败,改成public继承才符合状态机的多态需求
内容的提问来源于stack exchange,提问作者user63898
相关产品推荐
相关产品推荐

