平等比较std :: weak_ptr [英] Equality-compare std::weak_ptr

查看:206
本文介绍了平等比较std :: weak_ptr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想比较两个std :: weak_ptr或一个std :: weak_ptr和一个std :: shared_ptr的相等。

I want to compare two std::weak_ptr's or one std::weak_ptr and one std::shared_ptr for equality.

我想知道的是对象每个weak_ptr的/ shared_ptr的指向是一样的。
比较应该产生负结果,不仅是地址不匹配,而且如果底层对象被删除,然后用相同的地址偶然重构。

What I want to know is whether the object each of the weak_ptr's/shared_ptr's point to is the same. The comparison should yield negative results not just if the addresses don't match, but also if the underlying object was deleted and then reconstructed with the same address by chance.

基本上,我想要这个断言,即使分配器保留相同的地址:

So basically, I want this assertion to hold even if the allocator reserves the same address:

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模板不提供相等运算符,我理解有一个很好的理由

The weak_ptr templates do not provide equality operators, and as I understood that's for a good reason.

所以一个朴素的实现将看起来像这样:

So a naive implementation would look like this:

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在此期间过期,我将weak_ptr升级为shared_ptr并比较地址。

If the first weak_ptr expired in the meantime, it yields 0. If not, I upgrade the weak_ptr to a shared_ptr and compare the addresses.

问题是我必须锁定weak_ptr两次(一次)!恐怕花了太多时间。

The problem with this is that i have to lock the weak_ptr's twice (once)! I'm afraid that takes too much time.

我想出了这个:

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的所有者块是否不是beforet's和t's不在u之前,所以t == u。

Which checks if the owner block of u is not "before" t's and t's not before u's, so t == u.

这是否正常工作?做两个weak_ptr从不同的shared_ptr的创建总是比较不等于这种方式?
或者我错过了什么?

Does this work as I intend it? Do two weak_ptr's created from distinct shared_ptr's always compare as non-equal this way? Or did I miss something?

编辑:我为什么要这样做?
我想有一个具有共享指针的容器,并且我想提交对象的引用。
我不能使用迭代器,因为它们可能无效。我可以交出(整数)ID,但是这导致唯一性的问题,并且将需要地图类型和复杂的搜索/插入/删除操作。
这个想法是使用std :: set并给出指针本身(封装在一个包装类中)作为键,以便客户端可以使用weak_ptr来访问集合中的对象。

Why do I want to do this in the first place? I want to have a container with shared pointers, and I want to hand out references to the objects in it. I can't use iterators, since they may be invalidated. I could hand out (integer) ID's, but that leads to problems with uniqueness and would require a map type and complicate search/insertion/removal operations. The idea is to use a std::set and give out the pointers themselves (capsuled in a wrapper class) as keys, so that clients can use the weak_ptr's to access the objects in the set.

推荐答案

完全重写这个答案,因为我完全误解了。

Completely rewriting this answer because I totally misunderstood. This is a tricky thing to get right!

std :: weak_ptr 和<$ c $的常用实现方式与标准一致的c> std :: shared_ptr 是有两个堆对象:受管对象和控制块。引用同一对象的每个共享指针包含指向对象和控制块的指针,以及每个弱指针。控制块保持共享指针的数量和弱指针的数量的记录,并且当共享指针的数量达到0时解除管理对象的分配;当弱指针的数量也达到0时,控制块本身被释放。

The usual implementation of std::weak_ptr and std::shared_ptr that is consistent with the standard is to have two heap objects: the managed object, and a control block. Each shared pointer that refers to the same object contains a pointer to the object and to the control block, and each weak pointer likewise. The control block keeps a record of the number of shared pointers and the number of weak pointers, and deallocates the managed object when the number of shared pointers reaches 0; the control block itself is deallocated when the number of weak pointers also reaches 0.

这是复杂的,因为在共享或弱指针中的对象指针可以指向实际管理对象的子对象,例如一个基类,一个成员,或者甚至是被管理对象拥有的另一个堆对象。

This is complicated by the fact that the object pointer in a shared or weak pointer can point to a subobject of the actual managed object, e.g. a base class, a member, or even another heap object that is owned by the managed object.

S0 ----------______       MO <------+
   \__             `----> BC        |
      \_ _______--------> m1        |
     ___X__               m2 --> H  |
S1 -/      \__ __----------------^  |
    \___ _____X__                   |
    ____X________\__                |
W0 /----------------`---> CB -------+  
                          s = 2 
                          w = 1 

这里我们有两个共享指针,分别指向被管理对象和成员的基类,以及指向被管理对象所拥有的堆对象的弱指针;控制块记录两个共享指针和一个弱指针存在。

Here we have two shared pointers pointing respectively to a base class of the managed object and to a member, and a weak pointer pointing to a heap object owned by the managed object; the control block records that two shared pointers and one weak pointer exist. The control block also has a pointer to the managed object, which it uses to delete the managed object when it expires.

owner_before

The owner_before / owner_less semantics are to compare shared and weak pointers by the address of their control block, which is guaranteed not to change unless the pointer itself is modified; even if a weak pointer expires because all shared pointers have been destructed, its control block still exists until all weak pointers have also been destructed.

所以你的等于代码是绝对正确和线程安全的。

So your equals code is absolutely correct and thread safe.

问题是它不符合 shared_ptr :: operator == 因为它比较了对象指针,并且两个具有相同控制块的共享指针可以指向不同的对象(如上所示)。

The issue is that it's not consistent with shared_ptr::operator== because that compares the object pointers, and two shared pointers with the same control block can point to different objects (as above).

为了与 shared_ptr :: operator == 的一致性,写入 t.lock()== u 会绝对罚款;注意,如果它返回 true ,那么仍然不确定弱指针是另一个共享指针的弱指针;

For consistency with shared_ptr::operator==, writing t.lock() == u will be absolutely fine; note however that if it returns true then it's still not definite that the weak pointer is a weak pointer of the other shared pointer; it could be an alias pointer and so could still expire in following code.

但是,比较控制块有更少的开销(因为它不是一个别名指针, t需要查看控制块),如果不使用别名指针,将给出与 == 相同的结果。

However, comparing control blocks has less overhead (because it doesn't need to look at the control block) and will give the same results as == if you're not using alias pointers.

我认为这里的标准有些不足;添加 owner_equals owner_hash 将允许在无序中使用 weak_ptr 容器,并且给定 owner_equals 实际上比较弱指针的相等性是明智的,因为您可以安全地比较控制块指针然后对象指针,因为如果两个弱指针具有相同的控制块,那么您知道这两者或两者都未到期。对于下一版本的标准,或许。

I think that there's something of a deficiency in the standard here; adding an owner_equals and owner_hash would allow using weak_ptr in unordered containers, and given owner_equals it actually becomes sensible to compare weak pointers for equality, as you can safely compare the control block pointer then the object pointer, since if two weak pointers have the same control block then you know that either both or neither are expired. Something for the next version of the standard, perhaps.

这篇关于平等比较std :: weak_ptr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆