我正在创建一个将成为DAG一部分的类。构造函数将指向其他实例并使用它们初始化依赖项列表 初始化依赖列表后,它只能被缩短 - 实例永远不能作为自身或其任何子项的依赖项添加。
::std::shared_ptr
对于处理此问题很自然。对处理DAG进行了参考计数。
不幸的是,依赖项需要知道它们的依赖项 - 当依赖项更新时,它需要告诉所有依赖项。
这会创建一个可以用::std::weak_ptr
打破的简单循环。依赖关系可以忘掉那些消失的家属。
但我无法找到依赖者在构建时为自己创建::std::weak_ptr
的方法。
这不起作用:
object::object(shared_ptr<object> dependency)
{
weak_ptr<object> me = shared_from_this();
dependency->add_dependent(me);
dependencies_.push_back(dependency);
}
该代码导致在构造函数退出之前调用析构函数。
有没有一个很好的方法来处理这个问题?我对使用C ++ 11的解决方案非常满意。
答案 0 :(得分:9)
使用函数来构建图的节点,而不是构造函数。
std::shared_ptr<Node> mk_node(std::vector<std::shared_ptr<Node>> const &dependencies)
{
std::shared_ptr<Node> np(new Node(dependencies));
for (size_t i=0; i<dependencies.size(); i++)
dependencies[i].add_dependent(np); // makes a weak_ptr copy of np
return np;
}
如果您使用static
成员函数或friend
类的Node
,则可以创建实际的构造函数private
。
答案 1 :(得分:5)
基本上,你不能。您需要shared_ptr
或weak_ptr
来制作weak_ptr
,显然,自我只能以shared_ptr
的形式了解自己的weak_ptr
(否则就是没有必要计算参考)。当然,当对象尚未构建时,可能没有自我shared_ptr
。
答案 2 :(得分:1)
我理解您的问题在概念上与garbage collection问题有关。
GC是一个非模块化的功能:它处理程序的某些全局属性(更确切地说,实时数据是程序内部的全局,非模块化属性 - 有些情况下你无法处理以模块化和组合的方式。)。 AFAIK,STL或C ++标准库对全局程序功能没有多大帮助。可能的答案可能是使用(或实现自己)垃圾收集器;如果您能够在整个程序中使用它,Boehm's GC对您有用。
您还可以使用GC算法(甚至复制分代算法)来处理您的问题。
答案 3 :(得分:1)
你做不到。
我提出的最好的方法是将构造函数设为私有,并使用公共工厂函数将shared_ptr
返回给新对象;然后,工厂函数可以在构造后调用私有方法,初始化weak_ptr
。
答案 4 :(得分:1)
不幸的是,依赖关系需要知道他们的家属。这是因为当更新依赖项时,它需要告知所有依赖项。而且有一个微不足道的循环。幸运的是,这个循环可以用:: std :: weak_ptr打破。依赖关系可以忘掉那些消失的家属。
听起来,依赖项不能引用依赖项,除非依赖项存在。 (例如,如果依赖者被破坏,依赖性也会被破坏 - 毕竟这就是DAG)
如果是这种情况,你可以发出简单的指针(在这种情况下,this
)。如果依赖者还活着,你永远不需要检查依赖内部,因为如果依赖者死了,那么依赖也应该死了。
仅仅因为该对象归shared_ptr所有并不意味着它自己的所有指针都必须是shared_ptrs或weak_ptrs - 只需要定义关于指针何时失效的清晰语义。
答案 5 :(得分:1)
在我看来,你正试图将某些不同的项目混为一谈:一个对象(DAG中的一个节点),以及管理这些对象的集合。
class DAG {
class node {
std::vector<std::weak_ptr<node> > dependents;
public:
node(std::vector<weak_ptr<node> > d) : dependents(d) {}
};
weak_ptr<node> root;
};
现在,DAG可能只会持有weak_ptr<node>
而不是直接处理node
的实例。然而,对于节点本身而言,这或多或少是无关紧要的。它需要维护它包含的任何密钥/数据/等,以及它自己的依赖列表。
同时,通过将其嵌套在DAG内部(特别是如果我们将node
的类定义设为私有DAG),我们可以最小化对node
的访问,因此很少有其他代码具有关注node
的任何事情。根据具体情况,您可能还需要删除编译器默认生成的节点中的一些(大多数?)函数(例如,默认ctor,copy ctor,赋值运算符)。
答案 6 :(得分:0)
这也让我疯狂。
我考虑采用使用指针打破周期的策略......但是我真的没有找到这个因为我真的很喜欢当你在代码中看到它时,weak_ptr的意图是多么明确(你知道它在那里打破周期。)
现在我倾向于编写自己的weak_ptr类。
答案 7 :(得分:-1)
也许这会有所帮助:
继承自 enable_shared_from_this ,基本上持有weak_ptr
。
这样您就可以使用this->shared_from_this();
shared_ptr知道该类是否从类继承并在指向对象时使用类weak_ptr(防止2个共享指针以不同方式计数引用)
有关它的更多信息: cppreference