为什么将对象从一个智能指针移动到另一个会导致崩溃?

Why moving object from one smart pointer to another cause crash?

我对智能指针没有太多经验。我写了简单的状态栈,但我对这个函数有问题:

void StateStack::changeState(StatesType type)
{
    currentState = std::move(statesFactory(type));
}

这是指向对象的最后一个指针,所以智能指针删除了对象,我崩溃了。

State 是一个具有虚函数的基础class,MainMenu 和 LoadingScreen 继承自 State。

 int main()
    {
        Application application;
        application.run();
    }


Application::Application()
    : window(sf::VideoMode(1024, 768), "Test", sf::Style::Close),
    stateStack(State::Context(window))//...
{
}


StateStack::StateStack(State::Context settedContext):
    context(settedContext)
{
    currentState = statesFactory(StatesType::GameLoading);
}

std::unique_ptr<State> StateStack::statesFactory(StatesType type)
{
    std::unique_ptr<State> state;

    if (type==StatesType::GameLoading)      //etc. TODO
    {
        state.reset(new GameLoadingState(std::shared_ptr<StateStack>(this), context));
    }
    else if (type == StatesType::MainMenu)
    {
        state.reset(new MainMenuState(std::shared_ptr<StateStack>(this), context));
    }

    return state;
}

void GameLoadingState::update(sf::Time dt)
{
    //...

    if (timeSinceStart.asSeconds() > 5)
    {
        stack->changeState(StatesType::MainMenu);
    }
}

    class State
    {
    public:
        State(std::shared_ptr<StateStack> parent, Context settedContext);
        virtual void handleEvent(const sf::Event& event) = 0;
        //virtual ~State();
    protected:
        std::shared_ptr<StateStack> stack;
    private:
        Context context;
    };

最初 State 有虚拟析构函数并且在那里发生了崩溃。我认为这是不必要的,现在移动是问题的触发因素。

提前谢谢你,如果你指出我需要什么,我可以向你发送更多代码。

当您从原始指针构造共享指针时,该共享指针会将其自身(以及它的任何副本)视为原始指针的 "ownership group",并负责删除它。

所以你不想多次从同一个原始指针构造一个共享指针。在这里,您似乎正在多次从 this 构造共享指针。每个这样的构造都会认为自己是一个所有者——所以你会在同一个指针上得到多个删除。

正如@Jarod42 所指出的,enable_shared_from_this 可用于解决想要将额外的共享指针指向已由共享指针管理的对象的特定模式:

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

If I use enable_shared_from_this and later shared_from_this() I will get bad weak_ptr exception. I would have to have at least one shared pointer pointing to StateStack.

是的。请参阅上面 link 中的示例。如果感觉 "awkward" 可以按照您想要的方式设置共享指针,也许您应该重新考虑设计。

如果用英文表达的话,那么你现在的目标好像是:"When the last State in a StateStack goes away, the StateStack will automatically be destroyed." 是reasonable/necessary吗?

你的程序里有多少个StateStack?在生命周期管理方面,你能否做到这一点,以确保堆栈比状态寿命更长?然后你可以只使用普通引用从状态指向堆栈,并在你确定状态没有被使用后销毁堆栈。

如果您习惯于使用垃圾收集语言进行编程,您可能会尝试过度使用 shared_ptr。尽可能考虑一种更分层的方式来考虑所有权。