【发布时间】:2012-08-31 09:09:39
【问题描述】:
我想比较两个 std::weak_ptr 或一个 std::weak_ptr 和一个 std::shared_ptr 是否相等。
我想知道的是每个weak_ptr/shared_ptr指向的对象是否相同。 不仅如果地址不匹配,而且如果底层对象被删除然后偶然用相同的地址重建,则比较应该会产生负面结果。
所以基本上,即使分配器保留相同的地址,我也希望这个断言成立:
auto s1 = std::make_shared<int>(43);
std::weak_ptr<int> w1(s1);
s1.reset();
auto s2 = std::make_shared<int>(41);
std::weak_ptr<int> w2(s2);
assert(!equals(w1,w2));
weak_ptr 模板不提供相等运算符,据我了解,这是for a good reason。
所以一个简单的实现应该是这样的:
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::weak_ptr<U>& u)
{
return !t.expired() && t.lock() == u.lock();
}
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::shared_ptr<U>& u)
{
return !t.expired() && t.lock() == u;
}
如果第一个weak_ptr同时过期,它产生0。如果没有,我将weak_ptr升级为shared_ptr并比较地址。
这个问题是我必须锁定weak_ptr 两次(一次)!恐怕这需要太多时间。
我想出了这个:
template <typename T, typename U>
inline bool equals(const std::weak_ptr<T>& t, const std::weak_ptr<U>& u)
{
return !t.owner_before(u) && !u.owner_before(t);
}
template <typename T, typename U>
inline bool equals(const std::weak_ptr<T>& t, const std::shared_ptr<U>& u)
{
return !t.owner_before(u) && !u.owner_before(t);
}
它检查 u 的所有者块是否不在 t 的“之前”并且 t 不在 u 之前,所以 t == u。
这是否如我所愿?从不同的 shared_ptr 创建的两个weak_ptr 是否总是以这种方式比较不相等? 还是我错过了什么?
编辑:我为什么要首先这样做? 我想要一个带有共享指针的容器,并且我想分发对其中对象的引用。 我不能使用迭代器,因为它们可能会失效。我可以分发(整数)ID,但这会导致唯一性问题,并且需要地图类型和复杂的搜索/插入/删除操作。 这个想法是使用 std::set 并将指针本身(封装在包装类中)作为键,以便客户端可以使用weak_ptr 访问集合中的对象。
【问题讨论】:
-
“据我所知,这是有充分理由的。”如果你明白这是有充分理由的,那你为什么想要这样做呢?
-
我刚刚在并发应用程序中遇到了这个问题,好东西
owner_before()存在。对于我的用例,比较控制块是唯一明智的答案。
标签: c++ c++11 shared-ptr weak-ptr