2009-09-07 6 views
3

Si j'avais un conteneur STL, disons une liste de pointeurs que je pourrais supprimer comme dans l'exemple ci-dessous. Avec un conteneur de weak_ptrs cela ne fonctionne pas, car ils ne peuvent pas être comparés, car ils doivent d'abord être verrouillés. Que puis-je faire? Juste parce que j'ai cherché comme toujours pour trouver la réponse.Comment utiliser std :: remove sur un conteneur avec std :: tr1 :: weak_ptr?

void MyClass::RemoveItem(std::tr1::weak_ptr<Item> const & pItem) 
{ 
    mylist.remove(pItem); 
} 
+2

Et que se passe-t-il si le pointeur faible ne peut pas être verrouillé parce que ce qu'il pointe vers est parti? – Omnifarious

+0

En utilisant la réponse de sbk, p.lock() retournera un shared_ptr à p, qui ne correspondra pas à theItem.lock(), donc cela fonctionnera toujours. p.lock() ne lance jamais. –

Répondre

5

D'une part, vous pouvez simplement définir l'opérateur == pour tout weak_ptr. Je suis sûr qu'il y a une raison pour laquelle cela n'est pas implémenté, ça peut probablement vous mordre plus tard.

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

... et vous pourrez simplement appeler remove() comme d'habitude. C'est un peu extrême je suppose.

Si vous vous en tenez à l'approche remove_if(), vous pouvez vous débarrasser de la magie de liaison * en utilisant l'objet de fonction:

struct EqPredicate 
{ 
    const boost::weak_ptr<Item>& theItem; 

    EqPredicate(const boost::weak_ptr<Item>& item) : theItem(item) 
    { 
    } 

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

puis l'utiliser comme ceci:

mylist.remove_if(EqPredicate(pItem)); 

Il ressemble à plus de code, mais vous pouvez compresser la classe EqPredicate, elle est principalement creuse. En outre, il pourrait être fait modèle pour l'utiliser avec des listes contenant des types autres que Item.

Oh, et vous passez weak_ptrs par référence partout y compris votre fonction de comparaison.

* bind n'est pas gratuit en termes de performances. Si vous attendez beaucoup d'appels Remove() et que vous vous souciez beaucoup des performances, il peut être utile de l'éviter.

0

Créez une fonction pour comparer les weak_ptrs, puis lier un argument.

bool weak_ptr_comparsion(Item::wPtr a, Item::wPtr b) 
    { 
     return a.lock() == b.lock(); 
    } 

    void MyClass::RemoveItem(Item::wPtr const & pItem) 
    { 
     mylist.remove_if(std::tr1::bind(weak_ptr_comparsion, pItem, 
         std::tr1::placeholders::_1)); 
    } 

Ne pas oublier d'inclure <tr1/functional>

+1

On dirait que vous devriez utiliser un objet fonction à la place, et prendre des paramètres par référence. – rlbond

0

Je pense que le problème avec l'approche de sbk est l'opérateur weak_ptr == a le potentiel pour une course. Il n'y a aucune garantie de shared_ptr à a ou à b même si vous revenez de l'opérateur ==, ce qui facilite la mauvaise interprétation du code résultant.

Avec elle, il semble que le mieux que vous puissiez faire est:

if(a == b) { 
    boost::shared_ptr<Item> a_locked(a.lock()); 
    boost::shared_ptr<Item> b_locked(b.lock()); 
    // It is an error to assume a_locked == b_locked here 
    // It is an error to assume a.lock() == b.lock() here 
    // It is an error to assume a.get() or b.get() here 
} 

qui est pas utile. Maintenant, si vous étiez en train d'itérer sur un conteneur, vous pouvez toujours supprimer les itérateurs à ce stade, mais il y a beaucoup plus de cas où vous auriez fini par faire juste une fausse comparaison.

Questions connexes