5

最近我经常遇到需要类似于这种数据结构的东西的情况。

限制:C++03 标准。


 +-----+--------------+               +----+
 |node0| NodeDataRef ->-------------->|data|
 +-----+--------------+               +----+
 +-----+--------------+                ^^ ^
 |node1| NodeDataRef ->----------------+| |
 +-----+--------------+                 | |
 +-----+--------------+                 | |
 |node2| NodeDataRef ->-----------------+ |
 +-----+--------------+                   |
                                          |
 +-----+--------------+                   |
 |root | RootDataRef ->-------------------+
 +-----+--------------+              
  1. 有几个Node类,每个类都Node持有对“ ”(类、结构等——动态分配) 的同一个实例的NodeDataRef“引用”(想想)。shared_ptrData
  2. 还有一个“ Root”或“主”节点/类包含对相同“ ”的RootDataRef引用(这次,认为) 。weak_ptrData
  3. 当所有Nodes 被销毁时,data也被销毁并RootDataRef设置为0/ NULL。即NodeDataRef行为像shared_ptr<Data>RootDataRef行为像weak_ptr<Data>
  4. 然而,即使仍有活动NodeDataRef的 s,根节点也可以强制销毁数据。在这种情况下,所有NodeDataRef指向数据的 s 都设置为NULL/0并且RootDataRef也设置为0/ NULL

weak_ptr<Data>可以强制破坏所有联系shared_ptr<Data>

  1. 这种模式/智能指针类型有名称吗?
  2. 如何使用 Boost 或 Qt 4快速实现这一点?(“快速”意味着无需编写类来维护引用列表)
4

5 回答 5

4

这种模式/智能指针类型有名称吗?

据我所知,不,这不是具有常用名称的典型所有权模式。

如何使用 Boost 或 Qt 4 快速实现这一点?(“快速”意味着无需编写类来维护引用列表)

此用例没有预先打包的所有权策略,因为这会破坏共享所有权的意义。如果存在多个指向给定对象的共享指针,则根据定义,这些共享指针必须使该对象保持活动状态。如果给了我一个共享指针,则可以保证该对象在我释放它之前一直存在。

如果您希望一个主对象能够命令销毁指向的对象,而不管其他对象是否拥有指向它的共享指针,那么您将必须想出一些单独的机制来让它命令共享指针的所有持有者指向该对象释放它。

更新:

尽管存在“hacky”解决方案可以“快速”完成这项工作,但我不建议您使用其中任何一个。这种模式非常非典型,您希望当有人阅读您的代码时(包括几个月后的您) ,它会很明显。

您的意图应该通过主对象和其他所有者之间的显式通信模式来明确,而不是隐藏在包装器、自定义删除器或其他任何地方的某个地方。

于 2013-03-24T12:44:38.937 回答
0

你可以使用shared_ptr<T>weak_ptr<T>在哪里T = scoped_ptr<Data>。假设您可以Data使用 operator new 创建实例)。

shared_ptr应该使用make_shared<unique_ptr<Data>>(new Data(...));

根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")));

于 2013-03-24T13:02:54.307 回答
0

我不确定你为什么要这样做,但这是一个(非常)hackish 的解决方案,它还需要在每次访问 a 时运行一些额外的代码NodeDataRef(理想情况下作为该类的方法完成)。

与您的对象一起创建一个哨兵Data对象。给RootDataRef它一个拥有引用,给所有节点一个弱引用。然后,在每次访问 a 之前NodeDataRef,检查对哨兵的弱引用是否仍然有效。要强制从root中删除,请删除对哨兵的拥有引用,导致NodeDataRefs 中的所有弱引用变得无效。

于 2013-03-24T13:09:28.647 回答
0

一种易于实现(但不是最有效)的方法是拥有双 shared_ptr 层:
shared_ptr < shared_ptr < data >>
根将有一个指向它的弱指针,当您想要强制销毁时,您将重置内部 shared_ptr 数据(在锁下执行!)
所有其他节点将正常使用它,但在使用它之前必须检查内部 shared_ptr 的有效性。

于 2013-03-24T13:13:52.823 回答
0

没有人给出特定于 Qt 的答案(奇怪?),所以我会尝试一下,尽管我对共享指针类有点粗略。

似乎您可以将其生RootDataRef成为QSharedPointer并从中生成节点。创建第一个 后,使用QSharedPointer::toWeakRefNodeDataRef将 降级RootDataRef弱指针。这样,当您删除所有s 时,原始指针将被删除,并且应该(也许不是?)设置为零。NodeDataRefRootDataRef

如果您需要使用根删除原始对象,只需使用QWeakPointer::toStrongRef将其重新提升回强引用,删除它,所有节点都应自动分配为零。


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

于 2013-03-25T18:46:48.390 回答