平等,比较的std :: weak_ptr的(Equality-compare std::weak_

2019-06-27 21:49发布

我想比较两个标准:: weak_ptr的公司或一个的std :: weak_ptr的和一个标准:: 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的模板不提供平等的运营商,并作为我明白这是一个很好的理由 。

因此,一个天真的实现是这样的:

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 ==ü。

因为我想让它工作的呢? 做两的weak_ptr的FROM不同的shared_ptr的创建都是这样的比较结果为不相等? 还是我错过了什么?

编辑:为什么我想这样做摆在首位? 我想和共享指针的容器,我想伸手在它的对象引用。 我不能使用迭代器,因为它们可能会失效。 我伸手(整数)的ID,但是这导致与独特性的问题,需要一个地图类型和复杂化的搜索/插入/删除操作。 我们的想法是用std ::集并给出了指针本身(在包装类包胶)作为键,以便客户端可以使用的weak_ptr的访问在集中的对象。

Answer 1:

完全重写这个答案,因为我完全误解了。 这是一个棘手的事情得到正确的!

通常的实现的std::weak_ptrstd::shared_ptr是与标准相一致是有两个堆中的对象:被管理对象,以及控制块 。 引用同一对象的每个共享指针包含一个指向对象和控制块,并且每个弱指针同样。 控制块保持共享指针的数量和弱指针的数目的记录,并释放被管理对象时共享指针的数目达到0; 控制块本身被释放时弱指针的数量也达到0。

这是由以下事实:在一个共享的或弱指针对象指针可以指向实际管理对象的子对象,例如一个基类,成员,或者甚至由所述管理对象所拥有的另一堆对象复杂。

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

在这里,我们有分别指向一个基类被管理对象的,并成员两个共享指针,和弱指针指向被管理对象所拥有的堆对象; 两个共享指针和一个弱指针存在控制块的记录。 控制块还具有一个指向被管理对象,它使用到期时删除该管理对象。

所述owner_before / owner_less语义是可以通过控制块,它不能保证改变,除非指针本身是改性的地址共享和弱指针比较; 即使一个弱指针失效 ,因为所有共享指针已经被破坏,其控制块仍然存在,直到所有弱指针也被破坏。

所以你的equals代码是完全正确的线程安全的。

的问题是,它不具有一致shared_ptr::operator== ,因为其对所述对象指针,并用相同的控制块中的两个共享指针可以指向不同的对象(如上述)。

对于具有一致性shared_ptr::operator== ,写t.lock() == u将是绝对的罚款; 但是请注意,如果返回true那么它仍然不明确,弱指针的其它共享指针的弱指针; 它可能是一个别名指针,因此可以在下面的代码仍然失效。

然而,比较的控制块开销较少(因为它并不需要看控制块),将给予相同的结果==如果你不使用别名指针。


我认为有在这里标准缺乏的东西; 添加owner_equalsowner_hash将允许使用weak_ptr在无序的容器,并给予owner_equals它实际上变得懂事比较弱指针平等,你可以放心地比较控制块的指针,则对象的指针,因为如果两个弱的指针都具有相同的控制块,那么你知道,要么都有,或者都过期。 后话了标准的下一个版本,或许。



文章来源: Equality-compare std::weak_ptr