shared_ptr 和 unique_ptr 转换

新手上路,请多包涵

我处于不确定要使用哪种类型的智能指针的情况,因为我不确定我的班级的所有用例。我可以只使用共享指针,但是当我不一定需要共享所有权时,我不喜欢在代码中到处传递共享指针的想法。 Herb Sutter 的 这篇文章 说,如果有疑问,请使用 unique_ptr 并在必要时转换为 shared_ptr。这是我想做的,但我不清楚应该如何做,考虑这个例子:

 class Example
{
    public:
        Example(): _ptr(std::make_unique<Node>()) {}

        std::unique_ptr<Node>& getPtr()
        {
            return _ptr;
        }

    private:
        // I am unsure if I will eventually need shared ownership or not
        std::unique_ptr<Node> _ptr;
};

Example* example = new Example();

// Some function somewhere
void f()
{
    // I've decided I need shared ownership, converting
    std::shared_ptr<Node> ptr(std::move(example->getPtr()));

    // Oops, example is no longer valid...
}

如果有人对如何处理这种情况有更好的了解,我会很高兴听到它。

原文由 navark 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

我认为您在问一种优化问题。您希望 Example 使用 unique_ptr 因为它具有更简单和更有效的语义(解释您引用的文章)。但是,当需要时,您希望允许将指针转换为 shared_ptr

Example 应该简单地为此提供一个接口,并且当其用户调用该接口时,它本身需要从 unique_ptr 转换为 shared_ptr 。您可以使用状态模式来捕获实例是处于 unique_ptr 模式还是 shared_ptr 模式。

 class Example
{
    struct StateUnique;
    struct StateShared;
    struct State {
        State (std::unique_ptr<State> &s) : _state(s) {}
        virtual ~State () = default;
        virtual Node & getPtr () = 0;
        virtual std::shared_ptr<Node> & getShared() = 0;
        std::unique_ptr<State> &_state;
    };
    struct StateUnique : State {
        StateUnique (std::unique_ptr<State> &s)
            : State(s), _ptr(std::make_unique<Node>()) {}
        Node & getPtr () { return *_ptr.get(); }
        std::shared_ptr<Node> & getShared() {
            _state = std::make_unique<StateShared>(*this);
            return _state->getShared();
        }
        std::unique_ptr<Node> _ptr;
    };
    struct StateShared : State {
        StateShared (StateUnique &u)
            : State(u._state), _ptr(std::move(u._ptr)) {}
        Node & getPtr () { return *_ptr.get(); }
        std::shared_ptr<Node> & getShared() { return _ptr; }
        std::shared_ptr<Node> _ptr;
    };
public:
    Example(): _state(std::make_unique<StateUnique>(_state)) {}
    Node & getNode() { return _state->getPtr(); }
    std::shared_ptr<Node> & getShared() { return _state->getShared(); }
private:
    std::unique_ptr<State> _state;
};

如果状态机看起来很吓人(它应该是,因为它被过度设计了),那么您可以只在 Example 中维护两个指针,并且您的方法需要测试它需要使用哪一个。

 class Example
{
public:
    Example(): _u_node(std::make_unique<Node>()) {}
    Node & getNode() { return _u_node ? *_u_node.get() : *_s_node.get(); }
    std::shared_ptr<Node> & getShared() {
        if (_u_node) _s_node = std::move(_u_node);
        return _s_node;
    }
private:
    std::unique_ptr<Node> _u_node;
    std::shared_ptr<Node> _s_node;
};

原文由 jxh 发布,翻译遵循 CC BY-SA 3.0 许可协议

如果你有一个类,比如 UniqueResourceHolder ,它可以实现如下:

 class UniqueResourceHolder{
public:
  std::unique_ptr<Widget> ptr;
};

稍后,如果您想从 UniqueResourceHolder 获取所述资源并将其放入 SharedResourceHolder 中,如下所示:

 class SharedResourceHolder{
public:
  std::shared_ptr<Widget> ptr;
};

这样做的代码可能如下所示:

 {
  UniqueResourceHolder urh;
  SharedResourceHolder srh;
  //initialization of urh.ptr

  srh.ptr = std::shared_ptr<Widget>(urh.release());
}

UniqueResourceHolder 将不再有 Widget 它曾经有过,所以任何使用 urh 来获取小部件的尝试都是无效的(除非你用 a 重新填充它新的),但是 srh 现在将拥有该小部件并愿意分享。无论如何,这就是我理解您提供的链接中问题的答案的方式。我自己的两分钱是用 std::shared_ptr 替换出现的 std::unique_ptr 也是一件小事;您的程序为确保资源的唯一性仍然有效而遵循的任何业务逻辑,但是从利用 std::shared_ptr 的共享性质的业务逻辑开始,需要一些时间和精力来返工到独特的心态。

原文由 Altainia 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题