c++ - 安全的 enable_shared_from_this 用法

标签 c++ boost

请考虑以下简化示例:

#include "boost/shared_ptr.hpp"
#include "boost/smart_ptr/enable_shared_from_this.hpp"

using namespace boost;

class State : public boost::enable_shared_from_this<State>
{
public:
    shared_ptr<State> GetSelf()
    {
        return shared_from_this();
    };
    // returns following state
    virtual shared_ptr<State> Execute() = 0;
};

template<typename T>
shared_ptr<T> Create()
{
    return shared_ptr<T>(new T);
}

class MyState2;

class MyState1 : public State
{
    virtual shared_ptr<State> Execute()
    {
            if (change of state)
          return Create<MyState2>();
            else
              return GetSelf();
    };
};

class MyState2 : public State
{
    virtual shared_ptr<State> Execute()
    {
            if (change of state)
          return Create<MyState1>();
            else
              return GetSelf();
    }; 
};

int main(int argc, char* argv[])
{
    shared_ptr<State> pCurrentState = Create<MyState1>();  // <-- OK
//  State* pCurrentState(new MyState1);                    // <-- Runtime error
    while (...)
      pCurrentState = pCurrentState->Execute();

    return 0;
}

State 类是“框架”的一部分。它是轻量级状态机中用户定义状态的基础,其中每个状态返回其跟随者状态。如果状态没有改变,它会返回自己。框架用户可以任意派生自类 State。显然不允许创建派生类的“不受控制”实例(如果调用 GetSelf() 将导致运行时错误)。为了将用户指向正确的方向,提供了一个 Create() 函数模板来创建“受控”实例。由于我想尽可能地使用法万无一失,我如何才能确保用户不会创建任何不受 shared_ptr 控制的派生状态的实例?或者至少给出一个有意义的错误信息(在编译时?)如果他这样做了。

感谢您的帮助!

最佳答案

防止非托管实例的最简单方法是将每个派生类的构造函数设为私有(private)。您的工厂函数需要是它正在创建的类的友元或成员;如果您想保留工厂模板,则需要在派生类之前声明它,以便使其成为 friend :

template<typename T>
shared_ptr<T> Create()
{
    return shared_ptr<T>(new T);
}

class Derrived : public Base
{
private:
    friend shared_ptr<Derrived> Create<Derrived>();
    Derrived() {}
    // Client implementation goes here
};

但是,我通常建议您不要强制以特定方式管理类。如果类本身要求它们由共享指针管理以便正常运行(也就是说,它们需要调用 shared_from_this() 从他们的成员函数出于某种原因)。否则,只需组织您的框架,使其使用共享指针,任何使用该框架的人都必须这样做,而无需奇怪的强制机制。根本不需要 GetSelf(),因为如果您完全可以访问一个对象,您将始终有一个共享指针可供复制,并且不需要 enable_shared_from_this 除非类需要在内部访问共享指针(这是一件很不寻常的事情)。

更新:在您的用例中,我认为基类不可能强制使用共享指针(但如果我错了请纠正我)。在调用需要它们的函数时强制使用共享指针可能是有意义的。您将能够创建非托管对象,但不能对它们进行任何危险的操作。

class State : public boost::enable_shared_from_this<State>
{
public:
    // returns following state
    friend shared_ptr<State> Execute(shared_ptr<State> state) {
        return state->Execute();
    }
private:
    virtual shared_ptr<State> Execute() = 0;
};

class MyState : public State
{
    shared_ptr<State> Execute() {return shared_from_this();}
};

int main(int argc, char* argv[])
{
    shared_ptr<State> state1(new MyState);  // <-- OK
    State * state2(new MyState);            // <-- OK, but can't be used
    Execute(state1);                        // <-- OK
    // Execute(state2);                     // <-- Error
    // state2->Execute();                   // <-- Error
}

关于c++ - 安全的 enable_shared_from_this 用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7803789/

相关文章:

c++ - 初始化 vector 成员变量的正确方法

c++ - 测试字节顺序兼容性的工作流程

IOS 将 boost 类声明为类变量

c++ - 我应该对最简单的类型使用 boost::optional 来表示 nullable int double 等吗?

c++ - 访问另一个结构中的结构字段

c++ - 使用 QtWebSockets - 无法连接到 echoserver

c++ - "hello triangle"没有显示。是否有某些功能未正确使用?

c++ - 使用 boost 正则表达式库有什么问题?

c++ - Boost::asio get_io_service() 在 boost 1.70+ 中的替代方案

c++ - 使用 boost::program_options 和 push_back 阅读到 std::vector?