You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 13:21:24