为什么 class std::weak_ptr 没有运算符<?

Why is there no operator< for class std::weak_ptr?

我在地图中使用弱指针作为键。然而,当我尝试编译时,我收到了丑陋的消息,我将其解释为我缺少 std::weak_ptr 的比较运算符,显然,std::map 需要它,因为它对其元素进行排序根据键值。

但是,现在 weak_ptr class 是一种智能指针类型 class,因此,可以使用指向某些托管数据的指针。

这个 class 不提供 operator< 方法的基本实现是否有充分的理由?我的意思是,比较指针值对我来说似乎很明显,而且,如果需要它以不同的方式工作,那么应该能够扩展或重新定义该方法以获得预期的行为,而不是'是吗?

在此非常感谢您的见解。 感谢期待。

更新:有一种well-defined方法可以比较std::weak_ptr,参见。为了历史存档的目的,我会留下我的答案。


实施一个好的 operator< 需要从 weak_ptr 创建一个 shared_ptr 并调用它的 operator<。这是

  1. 一个"costly"操作
  2. undefined 当基础 shared_ptr 不再存在时。

通常很难获得 well-defined 和 weak_ptr 的高效排序。

请注意,您始终可以将自定义比较器传递给您的地图对象,您可以以任何您想要的方式实现它,并且只保留该对象的局部性。但是接下来就看你想出一个好的方法来做到这一点了。也许您可以使用指向连接 shared_ptr 的控制块的指针,但这是您无法访问的实现细节。所以我真的看不出有什么有意义的方法可以做到这一点。

我认为关键点在于(引自C++ Concurrency in Action, p. 194, emphasis mine)

Using hazard pointers like this relies on the fact that it's safe to use the value of a pointer after the object it references has been deleted. This is technically undefined behavior if you are using the default implementation of new and delete, so either you need to ensure that your implementation permits it, or you need to use a custom allocator that permits such usage.

提供 operator<() 需要读取原始指针值,这可能会导致未定义的行为(即,当 expired() return 为真时)。实际上没有办法保证比较成功,除非你先 lock() 并检查 return 值不为空。

std::owner_less 是在映射中将智能指针作为键排序的正确方法。

#include <map>
#include <memory>
#include <string>

struct Foo
{
};

using my_key = std::weak_ptr<Foo>;
using my_comp = std::owner_less<my_key>;

int main()
{
    auto m = std::map<my_key, std::string, my_comp>();

    auto p = std::make_shared<Foo>();
    auto p1 = std::make_shared<Foo>();

    m.emplace(p, "foo");
    m.emplace(p1, "bar");

    p.reset();
    p1.reset();
}