引用运算符与shared_ptr C++11的误解

Reference operator and shared_ptr C++11 misunderstanding

本文关键字:C++11 误解 ptr 运算符 shared 引用      更新时间:2023-10-16

我正在努力提高我的C++知识,需要帮助理解一些带有引用指针和shared_ptr的构造。

我有一个这样的结构:

IState *m_Loader;
void CStateManager::AttachState(E_STATE _estate, const IState &_state)
{
switch(_estate)
{
case STATE_LOADER:
    m_Loader = _state;
    break;
}
}

编译器告诉我,它无法将"Const IState转换为IState*"——我如何保存对象,以便以后使用它?我试着把自己从旧C语言的指针中解放出来,使用现代C++。

第二个问题是如何使用shared_ptr来实现状态模式?我看到使用shared_ptr是不可靠的,可能我需要weak_ptr,但我仍然无法想象如何实现这一点。

这里有完整的源代码,以了解我试图实现的内容。

#pragma once
#include <memory>
class IState;
class IStateManager
{
public:
    enum E_STATE
    {
    STATE_LOADER,
    STATE_MENU,
    STATE_GAME,
    STATE_EXIT
    };
virtual void SwitchState(E_STATE _estate) = 0;
virtual void AttachState(E_STATE _estate, const IState &_state) = 0;
virtual void Update() = 0;
public:
virtual ~IStateManager() {}
};
class IState
{
public:
virtual void Enter(const IStateManager &_statemgr) = 0;
virtual void Exit() = 0;
virtual void Sleep() = 0;
virtual void Update() = 0;
public:
virtual ~IState() {}
};
class CStateManager: public IStateManager
{
public:
void SwitchState(E_STATE _estate);
void AttachState(E_STATE _estate, const IState &_state);
void Update();
~CStateManager();
private:
IState *m_Loader;
IState *m_Menu;
IState *m_Game;
IState *m_Exit;
};
;
void CStateManager::SwitchState(E_STATE _estate)
{
}
void CStateManager::AttachState(E_STATE _estate, const IState &_state)
{
switch(_estate)
{
case STATE_LOADER:
    m_Loader = _state;
    break;
case STATE_MENU:
    break;
case STATE_GAME:
    break;
case STATE_EXIT:
    break;
}
}
void CStateManager::Update()
{
}
CStateManager::~CStateManager()
{
}

您最关心的是所引用对象的生存期,无论您使用引用、原始指针还是shared_ptr,都可能遇到问题,例如:

CStateManager test()
{
    CStateManager result;
    IState localIState;
    result.AttachState( CStateManager::STATE_LOADER, localIState );
    return result;
}
int main()
{
    CStateManager badLoader = test();
    return 0;
}

main函数中,如果访问了badLoader::m_Loader,则会出现segfault,因为m_Loader是指向已不存在的内存位置的指针。如果m_Loader是一个参考,甚至是一个shared_ptr,那么同样的事情显然也是正确的。

避免segfault的方法是使用m_Loader作为weak_ptr。所以你的代码会变成这样:

std::weak_ptr< IState > m_Loader;
void CStateManager::AttachState(E_STATE _estate, std::weak_ptr< IState > _state)
{
    switch(_estate)
    {
    case STATE_LOADER:
        m_Loader = _state;
        break;
    }
}

在调用函数中,您还必须更改创建localIState:的方式

CStateManager test()
{
    CStateManager result;
    std::shared_ptr< IState > localIState( new IState );
    result.AttachState( CStateManager::STATE_LOADER, localIState );
    return result;
}

如果您在main中访问badLoader::m_Loader,这将保护您免受分段故障的影响,因为std::weak_ptr在访问之前总是会检查其目标的存在。