通过 T* 从 std::set<shared_ptr<T>> 中移除元素

4

我有一组共享指针:

std::set<boost::shared_ptr<T>> set;

还有一个指针:

T* p;

我想要高效地移除等于“p”的set元素,但我不能使用任何集合成员或标准算法来完成此操作,因为T*是一种与boost::shared_ptr<T>完全不同的类型。我能想到几种方法:
  • 以某种方式从指针构造一个新的shared_ptr,而不会拥有指向的内存(理想的解决方案,但我不知道如何实现)
  • 包装/重新实现shared_ptr以便我可以执行上述操作
  • 自己在集合上进行二进制搜索

你为什么要有这个原始的T指针呢? - dalle
1
为什么不呢? 我经常在“工厂”类中使用智能指针,而在外部只使用裸指针/引用。外部不需要知道我如何管理我的对象。 - Matthieu M.
3个回答

9
T 构造一个带有 null_deletershared_ptr<T>(请参见 boost:::shared_ptr FAQ)。
struct null_deleter {
    void operator()(void const *) const { }
};

size_t remove_ptr_from_set(std::set<boost::shared_ptr<T>> &set, X* x)
{
    shared_ptr<X> px(x, null_deleter());
    return set.erase(px);
}

那样类型就兼容了,您不必担心临时shared_ptr删除任何对象。 或者,正如其中一条评论所说,如果您可以将T更改为继承enable_shared_from_this,则可以从您的对象获得正确的共享指针。

+1 真遗憾,我正要发布这个帖子。一开始我因为错误的想法认为删除器是shared_ptr类型的一部分而忽略了它。 - Daniel Earwicker
2
实际上,有一个单独的FAQ专门介绍如何从此处获取shared_ptr,该FAQ链接在此答案中。似乎有一个名为enable_shared_from_this的类模板,当继承时,会提供一个指向thisweak_ptr。请参见http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/enable_shared_from_this.html。 - Björn Pollex
@Space_C0wb0y:没错,但这取决于你是否可以改变T来继承它。并不总是可行的。 - Macke
我在使用带有空删除器的shared_ptr时遇到了一些问题:即使集合中存在与我构造的shared_ptr具有相同地址的shared_ptr,set::count仍返回零...因此我选择使用enable_shared_from_this解决方案。 - James
奇怪!shared_ptr的==和<运算符仅基于地址定义。(我刚刚检查过) - Macke

1
如果使用集合的原因是需要高效地查找类型为T的指针,那么显而易见的答案不是将其设置为共享指针的集合!相反,应该将该集合封装在一个类中,以管理集合中包含的指针的生命周期。

组合优于继承! - Eric
相比其他选项,这似乎是一项大量工作(这就是为什么我没有列出它!):唯一需要通过指针而不是shared_ptr进行查找的时间是在删除对象时(并且对象可能会持续存在直到最后一个用户的shared_ptr被销毁),因此我不能盲目地将对象的寿命与它们在容器中的存在联系起来。 - James
@Eric - 不完全是。 std :: set <boost :: shared_ptr <T>> 已经是组合,而不是继承。Neil 建议组合正确的事物,而不是组合错误的事物。 - Daniel Earwicker
@Dan - 我知道,我只是想指出解决方案不在继承中。 - Eric

1

如果您想要集合拥有对象,您可以使用 boost::ptr_set,或者如果您只想让集合存储对它们的引用,则可以使用 boost::reference_wrapper。如果您在代码中的某个地方使用了shared_ptr,则必须在所有地方使用它,否则可能会发生可怕的崩溃(悬空指针,已删除的对象等)。唯一的例外是 weak_ptr,这是一个指向由shared_ptr持有的一个对象的指针,但它不共享所有权。


该集合是对象的拥有者,但其他用户可能在从集合中删除后仍保留这些对象,因此boost::ptr_set不适用。 出于这个原因,我也不能使用reference_wrapperweak_ptr,因为在这两种情况下,用户可能会留下悬空引用。 - James
使用指针也存在悬空指针的风险。为什么不能使用shared_ptr来删除对象?为什么要在那里引入一个普通指针? - Björn Pollex
实际上,我想从储存的对象的成员函数中删除,因此在堆栈的更高处有一个 shared_ptr 引用该对象,但我不想在 this 指针已经可用时将其传递下去。基本上我想做:removeFromSet(this) - James

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