Инструменты пользователя

Инструменты сайта


// Удаление weak_ptr из std::list

Дано: контейнер примерно такого вида:

std::list< boost::weak_ptr<Item> > items;

Вместо boost::weak_ptr<> могу быть:

  • std::tr1::weak_ptr<>
  • std::weak_ptr<> для C++11

Задача: нужно удалить элемент по значению.

Казалось бы, просто сделай:

...
items.remove(value);
...

ан нет: для weak_ptr<> не определён оператор сравнения. Если потеоретизировать, можно предположить, почему так сделано: что бы гарантировать консистентность указателей при сравнении нужно их захватить (сделать value.lock()), т.е. создать два shared_ptr и уже их сравнивать, т.е. лишние накладные расходы.

Поэтому удаление можно делать так:

template <typename T>
bool operator == (const boost::weak_ptr<T>& a, const boost::weak_ptr<T>& b)
{
    return a.lock() == b.lock();
}

после такого std::list::remove(const T&) будет работать для всех типов. Можно и сузить до конкретного.

Либо использовать std::list::remove_if(Predicate), предикат объявить как:

struct EqPredicate
{
    const boost::weak_ptr<Item>& item;
 
    EqPredicate(const boost::weak_ptr<Item>& item)
        : item(item)
    {
    }
 
    bool operator () (const boost::weak_ptr<Item>& p) const
    {
         return p.lock() == item.lock();
    }
};

и использовать так:

std::list< boost::weak_ptr<Item> > items;
...
items.remove_if(EqPredicate(value));

Информация взята отсюда: http://stackoverflow.com/questions/1390340/how-can-i-use-stdremove-on-a-container-with-stdtr1weak-ptr

Вышесказанное верно для boost::weak_ptr, std::tr1::weak_ptr, std::weak_ptr

Комментарии