shared_ptr和unique_ptr转换

时间:2016-09-08 17:34:39

标签: c++

我遇到的情况是我不确定使用哪种类型的智能指针,因为我不确定我班级的所有用例。我可以使用共享指针,但我并不喜欢在代码中的任何地方传递共享指针的想法,因为我不一定需要共享所有权。 Herb Sutter的This article说,如果有疑问,请使用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...
}

如果有人更好地了解如何应对这种情况,我很高兴听到它。

3 个答案:

答案 0 :(得分:1)

如果你有一个班级,比如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获取窗口小部件的尝试都将无效(除非您使用新窗口重新填充它) ,但srh现在将拥有该小部件,并愿意分享。无论如何,这就是我在你提供的链接中理解问题答案的方式。我自己的两分钱是用std::unique_ptr代替std::shared_ptr的出现也是一件小事。您的程序遵循的任何业务逻辑以确保资源的唯一性仍然有效,但是从业务逻辑开始,您利用std::shared_ptr的共享特性将需要一些时间并专注于重新设计到独特的思维模式

答案 1 :(得分:1)

我认为你在问一种优化问题。您希望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;
};

答案 2 :(得分:0)

共享指针用于共享资源。如果您想共享资源,我会声明从头开始共享的所有内容,而不是进行特殊转换。

如果你想使用独特的指针你会说那里有'#34; must&#34;只存在一个指针,用于您已分配的资源。这并不限制您使用这些对象的方式。为什么不使用独特的指针和&#34;移动&#34;您的对象通过类实例和函数...如果您必须转换为您的指针,为什么不将其移动为唯一...

关于性能:据说,与原始指针相比,共享指针的速度慢了约6倍。唯一指针大约慢两倍。我当然在谈论访问。如果您确实拥有代码的性能关键部分,您仍然可以获得这些类的原始指针并进行操作。它甚至不必是一个指针,仍然有C ++ References。

我认为你应该决定你的对象是否会被共享&#34;或者&#34;感动&#34;并继续使用范式,而不是一直转换和改变。

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

不,不。如果从不同的地方调用,则传递多个引用。使用&#34;移动&#34;而不是运算符(例如type& operator=(type&& other)之类的声明)并传递您的唯一指针。