检查shared_ptr的容器是否包含指针

Check if container of shared_ptr contains a pointer?

本文关键字:是否 包含 指针 shared ptr 检查      更新时间:2023-10-16

使用观察者模式。我有一个类,例如称为Monitor,它监视对象的集合。类是一个Observer,其集合中的每个对象都是一个Subject。目前,该集合是作为shared_ptr的std::列表实现的。在Monitor类的Update方法中,我想检查更新是否来自其集合中的一个对象。

std::list<SomeSharedPointer> items_;
...
void Monitor::Update(Subject *subject)
{
    if(subject == something_)
    {
        DoSomething();
    }
    else if
    ??
    // if subject is one of the objects in our collection then do something..
}

主题这里是一个原始指针和我的集合是一个列表的shared_ptr。我如何有效地检查进入的主题是否属于我收藏的任何一件物品?

(注意我的编译器,msvc,支持lambdas,如果有一个算法解决方案需要一个)

我应该补充一下,我意识到我可以在容器上使用for循环,但我想知道是否有更时髦的方法。

更新2

SomeSharedPointerstd::shared_ptr<SomeType>的类型定义,其中SomeType派生自抽象类Subject(标准观察者模式实现)。SomeType将在某个时刻调用Notify(),这将为每个观察者调用Update()方法。

auto i = std::find_if(items_.begin(), items_.end(), 
    [=](const SomeSharedPointer& x) { return x.get() == subject; });
if (i != c.end())
{ 
    // Object found, and i is an iterator pointing to it
}

一个小的辅助方法可以使它更可读:

typedef std::list<SomeSharedPtr> ObserverCollection;
// You can also add a const version if needed
ObserverCollection::iterator find_observer(Subject* s)
{
    return std::find_if(items_.begin(), items_.end(), 
        [=](const SomeSharedPointer& x) { return x.get() == s; });
}

然后,如果需要迭代器

,可以这样使用它
auto i = find_observer(subject);
if (i != items_.end())
{
    // Object found
}

如果你不喜欢,就像这样:

if (find_observer(subject) != items_.end())
{
    ...
}

如果c++ 11不支持auto,请使用传统方式声明迭代器

for (auto iter = items_.begin(); iter != items_.end(); ++iter)
{
     if (subject == iter->get())
     {
         .. do stuff ..
     }
}

共享指针有.get()函数返回指针

既然你说观察者需要根据它正在监控的项目的状态做出决定,那么你应该向基类(你的问题中的Subject)添加一个方法,它返回一个定义项目状态的enum。然后根据状态,在更新方法中添加一个开关:

enum State{ STATE_1, STATE_2 };
void Monitor::Update(Subject *subject)
{
    switch( subject->getState() )
    {
      case STATE_1:
         // do something 1
         break;
      case STATE_2:
         // do something 2
         break;
      default:
         //error
    }
}

如果可能的话,您可以考虑将容器更改为能够提供更好的搜索行为的容器。例如,您可以使用std::set。每次插入的成本更高,但每次查找的速度更快。或者,std::unordered_set。插入和查找都很快,但迭代可能较慢。为了实现适当的比较,您可以创建一个helper类,以便将原始指针转换为具有无操作删除器的共享指针。

template <typename T>
struct unshared_ptr {
    std::shared_ptr<T> p_;
    unshared_ptr (T *p) : p_(p, [](...){}) {}
    operator const std::shared_ptr<T> & () const { return p_; }
    operator T * () const { return p_.get(); }
};

如果您的容器支持find方法,则:

typedef unshared_ptr<SomeType> unshared_some;
if (items_.end() != items_.find(unshared_some(subject))) {
    DoSomething();
}

上网试试!

如果你坚持使用std::list,你可以通过传递一个总是返回false的谓词来滥用remove_if方法,但是执行你的匹配测试。

bool matched = false;
auto pred = [subject, &matched](SomeSharedPtr &v) -> bool {
    if (!matched && v.get() == subject) {
        matched = true;
    }
    return false;
};
items_.remove_if(pred);
if (matched) {
    DoSomething();
} //...