智能指针/编码模式的名称

时间:2013-03-24 12:31:01

标签: c++ design-patterns boost qt4 smart-pointers

最近,我经常遇到需要与此数据结构类似的情况。

限制:C ++ 03标准。


 +-----+--------------+               +----+
 |node0| NodeDataRef ->-------------->|data|
 +-----+--------------+               +----+
 +-----+--------------+                ^^ ^
 |node1| NodeDataRef ->----------------+| |
 +-----+--------------+                 | |
 +-----+--------------+                 | |
 |node2| NodeDataRef ->-----------------+ |
 +-----+--------------+                   |
                                          |
 +-----+--------------+                   |
 |root | RootDataRef ->-------------------+
 +-----+--------------+              
  1. 有几个Node个类,其中每个NodeNodeDataRef“引用”(思考shared_ptr)保存到同一个“Data”实例( class,structure,whatever - 动态分配)。
  2. 还有一个“Root”或“主”节点/类,它将RootDataRef引用(这一次,weak_ptr}保持为相同的“Data
  3. 当所有Node被销毁时,data也会被销毁,RootDataRef设置为0 / NULL。即NodeDataRef shared_ptr<Data>RootDataRef的行为类似于weak_ptr<Data>
  4. 然而根节点可以强制销毁数据,即使仍有活跃的NodeDataRef。在这种情况下,指向数据的所有NodeDataRef都设置为NULL / 0,而RootDataRef也设置为0 / {{1} }。

  5. 即。 NULL可以强制销毁所有关联的weak_ptr<Data>

    1. 此模式/智能指针类型是否具有名称?
    2. 如何使用Boost或Qt 4快速实现此功能? (“快速”意味着不编写类来维护引用列表)

5 个答案:

答案 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 pointerRootDataRef降级为QSharedPointer::toWeakRef。这样,当你删除所有NodeDataRef时,原始指针将被删除,RootDataRef应该(可能不是?)设置为零。

如果您需要使用root删除原始对象,只需使用QWeakPointer::toStrongRef将其重新提升回强引用,删除它,并自动将所有节点分配为零。<​​/ p >


编辑:或者,你真的需要指针吗?如果这是共享数据而非实际共享对象的情况,您可以在QSharedDataPointer中考虑Qt的隐式共享方案,尤其是QExplicitlySharedDataPointer