在STL set中存储一个可变对象是否安全?

3
我想要一个容器来存储唯一的std::weak_ptrs。std:set需要operator<,可能是因为它将项目存储在树中。我的担心是,如果我按照显而易见的方式实现operator<(销毁的ptr = null ptr < 有效ptr),那么这个结果可能会在向容器添加项后发生变化,这可能会导致容器出错。
这样做是否安全?如果不是,有没有建议的容器?
谢谢

2
我的gcc上似乎没有默认的std::less用于weak_ptrs。 - Sam
“operator <” 似乎没有为 “weak_ptr” 定义,因此“less”无法正常工作。 - skypjack
能有所帮助吗?http://en.cppreference.com/w/cpp/memory/owner_less - skypjack
@Sam:哦,好的,在这种情况下,请使用std::owner_less<std::weak_ptr<T>>作为谓词。 - Kerrek SB
太棒了,owner_less看起来完美无缺。 - Sam
2个回答

1

user3159253是正确的。在这里找到完整的答案:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1590.html

     weak_ptr::operator<

由于weak_ptr可以在任何时候过期,因此无法根据其值对weak指针进行排序。访问已删除指针的值会引发未定义行为,reinterpret_cast技巧也无效,因为下一个新表达式可能会重用相同的指针值。使用p.lock().get()进行排序也存在类似缺陷,因为这意味着当p或q过期时,p < q的值可能会发生变化。如果p和q是std::set的成员,则会破坏其不变性。唯一实用的替代方案是按照控制块的地址对弱指针进行排序,因为当前规范有效地要求这样做。

那篇论文是一个不错的发现。首先,我预期弱指针的顺序在过期后会被保留。今天我学到了! - sehe

0

除非您使用基于所有者的比较(与基于值的比较相对,后者甚至未定义为weak_ptr,尝试使用operator<会导致错误),否则不能将weak_ptr用作键。

问题在于它们可能会过期,您的容器(包括setmap)的排序将不再一致。

正如Kerrek SB所指出的那样(请原谅我,但移动应用程序不允许我正确链接用户),并且正如您可以从我的评论中的链接中阅读到的那样,您可以依赖C++11开始提供的std::owner_less

一个有效的方法是使用以下定义的set

std::set<std::weak_ptr<C>, std::owner_less<std::weak_ptr<C>>>

请注意,owner_less 可以更简洁,因为它会自动推断类型。
请记住,这种方法并不能阻止您在访问 set 时调用 expired 方法,因为即使有序,它仍然可能包含已过期的对象。
此外,请注意,过期的 weak_ptr 和空的 weak_ptr 之间存在巨大的区别,因此基于所有者的比较可能不是那么直观,即使使用上述方法后过期也不应该影响它。 这里 一些 链接

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接