c++ - 图节点父列表中的 weak_ptr VS shared_ptr

标签 c++ c++11 shared-ptr directed-acyclic-graphs

我有一个由 Graph 和 Node 类实现的有向无环图。每个节点都有一个指向子节点的指针列表和一个指向父节点的指针列表。我最近添加了父级,因为一些算法需要快速访问父级列表,而且图很小,每个节点只有很少的连接,所以没有内存问题。

子列表使用 std::shared_ptr 以便节点至少在它们有父节点时保留在内存中。但是我不希望节点拥有它的父节点,所以我使用 weak_ptr 作为指向父节点的指针。

但是后来算法出了问题。算法必须从 weak_ptr 创建一个新的 shared_ptr,所以我不能直接使用 operator==,并且使用标准函数如 std::find() 需要编写一个调用 my_weak_ptr.lock() 然后比较它的 lambda 函数到一些 shared_ptr。

如果我切换到 shared_ptr,负责删除节点的代码中的任何小错误都可能导致内存泄漏。或者,如果我有一个指向已删除节点的指针,代码将能够访问一个不应该存在的节点,因此查找一些错误可能会变得更加困难。但就不取消引用/删除/等而言,使用 shared_ptr 与 weak_ptr 一样安全。当不应该的时候,(所以它比原始 C++ 指针更好)和 std::find() 可以直接使用,因为 shared_ptr 可以被取消引用,这与 weak_ptr 不同。

这里是否有“更好”的设计,或者它是这种特定情况的问题,具体取决于例如如果我执行 weak_ptr::lock() 的额外操作或冒难以发现错误的风险,这有多大关系?

最佳答案

正如您自己所说,在两个方向上使用 shared_ptr 会产生循环,从而造成内存泄漏并且很难找到和打破 - 您将(几乎)失去 shared_ptr 提供的所有好处。所以 weak_ptr 应该是。

您说您的算法必须锁定 weak_ptr - 我不敢苟同。算法必须从节点获取父 shared_ptr。节点的任务是锁定父 weak_ptr 并返回结果,要么正确设置为父节点,要么为 NULL。

这是一个实现细节,节点是将它们的父节点存储为 shared_ptr 还是 weak_ptr。通过仅向任何客户端提供 shared_ptr 来封装该细节。

class Node
{
  /* ... */
  std::weak_ptr<Node> parent;
public:
  std::shared_ptr<Node> getParent()
  {
    return parent.lock();
  }
};

编辑: 当然,如果有多个父级,概念上同样适用。

编辑2: 在评论中,您提到算法会迭代您的 parent 列表,因此有必要为每个算法编写 lambda。如果您经常使用这些算法,请考虑编写一个自动锁定目标 weak_ptr 并返回一个 shared_ptr 的迭代器适配器:

template <class WPIterator>
struct LockTheWeakIterator
{
  //static_assert that WPiterator's value_type is some weak_ptr
  //typedef all those iterator typedefs
  typedef typename WPIterator::value_type::element_type element_type;

  shared_ptr<element_type> operator*()
  { return iter->lock(); }

  //provide all the other operators - boost.operators might help with that...

  WPIterator iter;
};

template <class IT>
LockTheWeakIterator<It> lockTheWeak(It iter);


//somewhere...
auto theParentIter = std::find_if(lockTheWeak(parents.begin()), 
  lockTheWeak(parents.end()), 
  whatIAmLookingFor);

关于c++ - 图节点父列表中的 weak_ptr VS shared_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14562464/

相关文章:

c++ - 替换共享指针的内容?

支持所有 C++11 并发功能的 C++ 编译器?

c++ - C++11 中 override 和 virtual 的组合

c++ - 为什么使用一个 vs 另一个 : `boost::shared_array` VS `boost::shared_ptr<std::vector>` ?

C++ 数据类型大小/范围在 Linux 上的显示

c++ - 通过引用修改作用域枚举

使用 shared_ptr 作为参数时的 C++/CLI "could not import member"警告

c++ - 给定两个字谜词。交换一个单词(仅允许交换相邻的字母)以到达另一个单词

c++ - 模板化递归数据类型

c++ - 无法在 64 位 mac 上为 Xcode 中的 C++ 项目构建 opencv 2.4