缺少shared_ptr和weak_ptr之间的相等性

时间:2012-06-10 11:10:04

标签: c++ c++11 shared-ptr

虽然我理解为什么operator==shared_ptr没有unique_ptr,但我想知道为什么shared_ptrweak_ptr没有weak_ptr。特别是因为您可以通过shared_ptr上的引用创建lhs.get() == rhs.get()。 我认为99%的时间你想要{{1}}。我现在要继续向我的代码介绍,除非有人能给我一个充分的理由,为什么不应该做这样的事情。

3 个答案:

答案 0 :(得分:16)

weak_ptr没有get()方法,因为您需要在访问基础指针之前显式锁定weak_ptr。明确这一点是一个深思熟虑的设计决策。如果转换是隐式的,那么在编写从shared_ptr获取的基础指针仍然被检查的同时,如果要销毁对象的最后weak_ptr,那么编写将是不安全的代码将非常容易。 / p>

This boost page很好地描述了陷阱以及为什么weak_ptr具有如此有限的界面。

如果您需要进行快速比较,那么您可以执行shared == weak.lock()。如果比较结果为真,那么您知道weak必须仍然有效,因为您对同一个对象保持单独的shared_ptr。如果比较返回false,则没有这样的保证。

答案 1 :(得分:4)

因为它有成本。

weak_ptr就像一个观察者,而不是真正的指针。要使用它进行任何工作,首先需要使用shared_ptr方法从中获取lock()

这具有获得所有权的效果,但它与复制常规shared_ptr(计数增量等等)一样昂贵,因此这不是一件轻而易举的事。

因此,如果不提供==,您将被迫退回并实际检查您是否真的需要这样做。

答案 2 :(得分:3)

正如其他答案所指出的那样,仅比较底层指针将是危险的。对于其中一个,请考虑以下情形:对对象存在弱引用A,该对象随后被删除,因此弱引用到期。然后,在所述删除所释放的存储器中分配另一个对象,该对象具有相同的地址。现在,即使弱指针最初指向另一个对象,底层指针也相同!

正如其他答案所建议的那样,一种方法是比较shared == weak.lock()。由于如果弱指针过期,lock()将返回nullptr(而不是伪造的指针),因此他的工作是确定它们是否相等(只要shared != nullptr)。但是,这有两个问题:

  • 当弱指针到期时它会停止工作,在这种情况下,比较会更改;到期后,仅当shared == nullptr时返回true。如果比较必须保持稳定,例如在unordered_mapunordered_set中用作比较键时,这可能很危险。
  • lock()是一个相对昂贵的操作。

幸运的是,有更好的方法可以做到这一点。 weak_ptrshared_ptr都还存储了一个指向控制块的指针,该存储块存储了引用计数,并且只要保留了引用,该生存期就会超过原始对象对此。要检查它们是否引用相同的对象,我们要做的就是比较控制块指针。这可以通过owner_before方法完成:

template<class T>
bool owner_equals(std::shared_ptr<T> &lhs, std::weak_ptr<T> &rhs) {
    return !lhs.owner_before(rhs) && !rhs.owner_before(lhs);
}

如果您想知道两个std::weak_ptr是否(一次)引用同一对象,则此方法甚至可以用于相互比较,因为控制块将持续(至少)个时间。所有弱引用。

请记住,如果您使用std::shared_ptr的别名功能,这可能不会产生预期的结果,该功能使您可以使用相同的控制块创建两个std::shared_ptr实例。尽管如此,存储不同的指针。