11

虽然我确实理解为什么没有operator==for shared_ptrand unique_ptr,但我想知道为什么没有 for shared_ptrand weak_ptr。特别是因为您可以weak_ptr通过对shared_ptr. 我会假设 99% 的时间都是你想要的lhs.get() == rhs.get()。我现在将继续并将其引入我的代码中,除非有人可以给我一个很好的理由,为什么不应该做这样的事情。

4

3 回答 3

17

weak_ptr没有get()方法,因为您需要显式锁定weak_ptr才能访问底层指针。明确这一点是一个深思熟虑的设计决定。如果转换是隐式的,那么很容易编写不安全的代码,如果shared_ptr对象的最后一个要被销毁,而从 中获得的底层指针weak_ptr仍在检查中。

这个提升页面很好地描述了陷阱以及为什么weak_ptr界面如此有限。

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

于 2012-06-10T11:22:03.697 回答
4

因为它是有代价的。

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

这具有获得所有权的效果,但它与复制常规shared_ptr(计数增量等)一样昂贵,所以它不是微不足道的。

因此,如果不提供==,您将被迫退后一步并实际检查您是否真的需要这个。

于 2012-06-10T11:16:29.710 回答
3

正如其他答案所指出的那样,简单地比较底层指针是危险的。例如,考虑以下场景:一个对象的弱引用 A 存在,该对象随后被删除,因此弱引用过期。然后,在由所述删除释放的内存中分配另一个对象,该对象具有相同的地址。现在底层指针是相同的,即使弱指针最初指向不同的对象!

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

  • 当弱指针过期时它停止工作,在这种情况下比较会改变;过期后,只有在shared == nullptr. 这在比较必须保持稳定的情况下可能很危险,例如将其用作unordered_mapor中的键时unordered_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_ptrs,因为控制块将(至少)与所有弱引用一样长。

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

于 2018-07-30T09:44:28.253 回答