我遇到的情况是我不确定使用哪种类型的智能指针,因为我不确定我班级的所有用例。我可以使用共享指针,但我并不喜欢在代码中的任何地方传递共享指针的想法,因为我不一定需要共享所有权。 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...
}
如果有人更好地了解如何应对这种情况,我很高兴听到它。
答案 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)
之类的声明)并传递您的唯一指针。