最近,我经常遇到需要与此数据结构类似的情况。
限制:C ++ 03标准。
+-----+--------------+ +----+
|node0| NodeDataRef ->-------------->|data|
+-----+--------------+ +----+
+-----+--------------+ ^^ ^
|node1| NodeDataRef ->----------------+| |
+-----+--------------+ | |
+-----+--------------+ | |
|node2| NodeDataRef ->-----------------+ |
+-----+--------------+ |
|
+-----+--------------+ |
|root | RootDataRef ->-------------------+
+-----+--------------+
Node
个类,其中每个Node
将NodeDataRef
“引用”(思考shared_ptr
)保存到同一个“Data
”实例( class,structure,whatever - 动态分配)。 Root
”或“主”节点/类,它将RootDataRef
引用(这一次,weak_ptr
}保持为相同的“Data
” Node
被销毁时,data
也会被销毁,RootDataRef
设置为0
/ NULL
。即NodeDataRef
shared_ptr<Data>
和RootDataRef
的行为类似于weak_ptr<Data>
NodeDataRef
。在这种情况下,指向数据的所有NodeDataRef
都设置为NULL
/ 0
,而RootDataRef
也设置为0
/ {{1} }。即。 NULL
可以强制销毁所有关联的weak_ptr<Data>
。
答案 0 :(得分:4)
此模式/智能指针类型是否具有名称?
据我所知,不,这不是具有常用名称的典型所有权模式。
如何使用Boost或Qt 4快速实现此功能? (“快速”意味着不编写类来维护引用列表)
此用例没有预打包的所有权政策,因为这会破坏共享所有权。如果存在指向给定对象的多个共享指针,则根据定义,这些共享指针必须使该对象保持活动状态。如果给我一个共享指针,那就是保证对象存在直到我释放它。
如果您希望一个主对象能够命令销毁指向对象,无论其他对象是否拥有指向它的共享指针,那么您将必须设置一些单独的机制来让它命令所有持有者共享指向该对象的指针以释放它。
<强>更新强>
尽管存在“hacky”解决方案以“快速”完成此工作,但我不建议您使用其中任何一种。这种模式非常不合适,当有人读取您的代码(包括您在几个月后)时,您希望它明显。
您的意图应该通过主对象和其他所有者之间的显式通信模式来明确,而不是隐藏在包装器,自定义删除器或其他任何内容中。
答案 1 :(得分:0)
您可以使用shared_ptr<T>
和weak_ptr<T>
T = scoped_ptr<Data>
。假设您可以使用operator new创建Data
个实例。
shared_ptr
应使用make_shared<unique_ptr<Data>>(new Data(...));
root weak_ptr可以通过调用root.lock().reset()
template <typename T>
struct RootHandle : public boost::weak_ptr< boost::scoped_ptr<T> >
{
typedef boost::weak_ptr< boost::scoped_ptr<T> > weak_type;
typedef boost::shared_ptr< boost::scoped_ptr<T> > strong_type;
RootHandle() {}
RootHandle(const weak_type& impl)
:weak_type(impl) {}
T* get() const
{
strong_type x = lock();
return (x) ? x->get() : 0;
}
void reset()
{
strong_type x = lock();
if (x)
x->reset();
}
};
template <typename T>
struct NormalHandle : public boost::shared_ptr< boost::scoped_ptr<T> >
{
public:
typedef boost::shared_ptr< boost::scoped_ptr<T> > strong_type;
NormalHandle() {}
NormalHandle(const strong_type& impl)
:strong_type(impl) {}
T* get() const
{
boost::scoped_ptr<T>* ppx = strong_type::get();
return (0 != ppx) ? ppx->get() : 0;
}
};
新NormalHandles的初始化如下所示:
NormalHandle<Data> handle1(boost::make_shared< boost::scoped_ptr<Data> >(new Data(4, 3, "abc")));
答案 2 :(得分:0)
我不确定你为什么要这样做,但这里有一个(非常)hackish解决方案,它还需要在每次访问NodeDataRef
时运行一些额外的代码(理想情况下作为一种方法完成)类)。
与Data
对象一起创建一个sentinel对象。给RootDataRef
一个拥有引用,所有节点都是弱引用。然后,在每次访问NodeDataRef
之前,检查对标记的弱引用是否仍然有效。要强制从root
删除,请删除对标记的拥有引用,导致NodeDataRef
中的所有弱引用无效。
答案 3 :(得分:0)
一种易于实现(但不是最有效)的方法是使用双重shared_ptr层:
shared_ptr&lt; shared_ptr&lt;数据&gt; &GT; 强>
根将有一个弱指针,当你想要一个强制销毁时,你将重置内部shared_ptr数据(在锁定下执行!)
所有其他节点将正常使用它,但在使用之前必须检查内部shared_ptr的有效性。
答案 4 :(得分:0)
没有人给出一个特定于Qt的答案(很奇怪?),所以我会给它一个解决方法,虽然我对共享指针类有点粗糙。
您似乎可以将RootDataRef
生成为QSharedPointer并从中生成节点。创建第一个NodeDataRef
后,使用a weak pointer将RootDataRef
降级为QSharedPointer::toWeakRef。这样,当你删除所有NodeDataRef
时,原始指针将被删除,RootDataRef
应该(可能不是?)设置为零。
如果您需要使用root删除原始对象,只需使用QWeakPointer::toStrongRef将其重新提升回强引用,删除它,并自动将所有节点分配为零。</ p >
编辑:或者,你真的需要指针吗?如果这是共享数据而非实际共享对象的情况,您可以在QSharedDataPointer中考虑Qt的隐式共享方案,尤其是QExplicitlySharedDataPointer。