fat*_*yte 28 c++ shared-ptr weak-ptr c++11
我想比较两个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));
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
如果第一个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);
}
Run Code Online (Sandbox Code Playgroud)
检查u的所有者块是否在"t"之前并且t不在u之前,所以t == u.
这是否符合我的意图?从不同的shared_ptr创建的两个weak_ptr总是以这种方式比较为不相等吗?还是我错过了什么?
编辑:我为什么要首先这样做?我想要一个带有共享指针的容器,我想分发对它中对象的引用.我不能使用迭代器,因为它们可能无效.我可以分发(整数)ID,但这会导致唯一性问题,并且需要地图类型和复杂的搜索/插入/删除操作.我们的想法是使用std :: set并将指针本身(在包装类中封装)作为键给出,以便客户端可以使用weak_ptr来访问集合中的对象.
eca*_*mur 27
完全重写这个答案,因为我完全误解了.要做对,这是一个棘手的事情!
通常的实现的std::weak_ptr并且std::shared_ptr是与标准相一致是有两个堆中的对象:被管理对象,和一个控制块.引用同一对象的每个共享指针包含指向对象和控制块的指针,同样包含每个弱指针.控制块记录共享指针的数量和弱指针的数量,并在共享指针的数量达到0时解除分配管理对象; 当弱指针的数量也达到0时,控制块本身被释放.
由于共享或弱指针中的对象指针可以指向实际托管对象的子对象,例如基类,成员,甚至是托管对象拥有的另一个堆对象,因此这很复杂.
S0 ----------______ MO <------+
\__ `----> BC |
\_ _______--------> m1 |
___X__ m2 --> H |
S1 -/ \__ __----------------^ |
\___ _____X__ |
____X________\__ |
W0 /----------------`---> CB -------+
s = 2
w = 1
Run Code Online (Sandbox Code Playgroud)
这里我们有两个共享指针,分别指向托管对象和成员的基类,以及指向托管对象拥有的堆对象的弱指针; 控制块记录存在两个共享指针和一个弱指针.控制块还有一个指向托管对象的指针,用于在托管对象过期时删除托管对象.
的owner_before/ owner_less语义可以通过控制块,它不能保证改变,除非指针本身是改性的地址共享和弱指针比较; 即使弱指针因为所有共享指针都被破坏而到期,它的控制块仍然存在,直到所有弱指针都被破坏为止.
所以你的equals代码绝对正确且线程安全.
问题是它不一致,shared_ptr::operator==因为它比较了对象指针,两个具有相同控制块的共享指针可以指向不同的对象(如上所述).
为了保持一致shared_ptr::operator==,写作t.lock() == u绝对没问题; 但请注意,如果它返回,true那么它仍然不能确定弱指针是另一个共享指针的弱指针; 它可能是一个别名指针,所以仍然可以在下面的代码中过期.
但是,比较控制块的开销较小(因为它不需要查看控制块),并且会给出与==不使用别名指针相同的结果.
我认为这里的标准有些不足之处; 添加一个owner_equals并owner_hash允许weak_ptr在无序容器中使用,并且鉴于owner_equals它实际上比较弱指针的相等性是合理的,因为你可以安全地比较控制块指针然后比较对象指针,因为如果两个弱指针具有相同的控制块,那么你知道无论是两者还是两者都没有过期.也许是下一版标准的东西.
| 归档时间: |
|
| 查看次数: |
12065 次 |
| 最近记录: |