2010-04-08 16 views
4

J'ai un std::list de boost::shared_ptr<T> et je veux en retirer un élément mais j'ai seulement un pointeur de type T * qui correspond à l'un des éléments de la liste.Quelle est la bonne façon de supprimer un boost :: shared_ptr d'une liste?

Cependant je ne peux pas utiliser myList.remove(tPtr) Je devine parce que shared_ptr n'implémente pas == pour son type d'argument de modèle.

Ma pensée immédiate était d'essayer myList.remove(shared_ptr<T>(tPtr)) qui est syntaxiquement correct, mais il va se bloquer à partir d'une double suppression puisque le shared_ptr temporaire a un use_count séparé.

std::list< boost::shared_ptr<T> > myList; 

T* tThisPtr = new T(); // This is wrong; only done for example code. 
         // stand-in for actual code in T using 
         // T's actual "this" pointer from within T 
{ 
    boost::shared_ptr<T> toAdd(tThisPtr); // typically would be new T() 
    myList.push_back(toAdd); 
} 

{ 
    //T has pointer to myList so that upon a certain action, 
    // it will remove itself romt the list 

    //myList.remove(tThisPtr);      //doesn't compile 
    myList.remove(boost::shared_ptr<T>(tThisPtr)); // compiles, but causes 
                // double delete 
} 

Les options que je vois restants sont à utiliser std :: trouver une coutume comparer ou faire une boucle dans la liste force brute et de trouver moi-même, mais il semble qu'il devrait y avoir une meilleure façon. Est-ce que je manque quelque chose d'évident, ou est-ce simplement une utilisation non-standard pour faire une suppression de la façon propre/normale?

Répondre

3

enable_shared_from_this peut aider à résoudre votre problème, mais il faudra que les types que vous utilisez dans la liste en dérivent:

Si le type permet cette fonctionnalité, vous peut obtenir le pointeur partagé à partir de l'objet lui-même en appelant shared_from_this().

+0

+1 pour la solution la plus directe au problème. –

4

std :: Liste des membres remove_if est ce que vous avez besoin:

Définir un prédicat

template <typename T> struct shared_equals_raw 
{ 
    shared_equals_raw(T* raw) 
    :_raw(raw) 
    {} 
    bool operator()(const boost::shared_ptr<T>& ptr) const 
    { 
     return (ptr.get()==_raw); 
    } 
private: 
    T*const _raw; 
}; 

vous pouvez appeler

myList.remove_if(shared_equals_raw(tThisPtr)); 

avoir la liste nettoyer les noeuds qui ont shared_ptrs à tThisPtr.

(non testé, donc peut-être que certains trucs syntaxiques ont besoin d'être corrigés).

Le conseil de Michael Burr concernant enable_shared_from_this est bon; il vaudrait mieux éviter d'avoir le tThisPtr brut en jeu.

+0

Désolé, je ne voulais pas marcher sur vos orteils, je ne vous avais pas déjà eu la solution. +1 pour la bonne réponse, -0 pour la syntaxe incorrect-ish. :) – GManNickG

+3

+1 pour être correct mais ... GAH MY EYES! NE PEUT PAS FAIRE FACE AU MOTIF D'INDENTATION ÉTRANGE! :) –

5

Vous avez raison, nous ne pouvons pas comparer directement les pointeurs. Mais il existe remove_if, et nous pouvons spécifier notre propre prédicat. La solution:

template <typename T> 
struct ptr_contains_predicate 
{ 
    ptr_contains_predicate(T* pPtr) : 
    mPtr(pPtr) 
    {} 

    template <typename P> 
    bool operator()(const p& pPtr) const 
    { 
     return pPtr.get() == mPtr; 
    } 

    T* mPtr; 
}; 

template <typename T> 
ptr_contains_predicate<T> ptr_contains(T* pPtr) 
{ 
    return ptr_contains_predicate<T>(pPtr); 
} 

Gardez juste le prédicat ci-dessus dans un en-tête quelque part, et vous pouvez l'utiliser où vous voulez.

myList.remove_if(ptr_contains(tThisPtr)); 

La meilleure solution est de ne jamais perdre la main sur la shared_ptr en premier lieu, afin que nous puissions simplement utiliser remove, mais ce qui précède est sans danger de toute façon. Pouvez-vous utiliser le pointeur partagé pour le supprimer?

+0

Merde vous! (Battez-moi par une minute ...) +1 –

+4

Pas besoin d'un foncteur en C++ 0X: myList.remove_if ([ptr] (shared_ptr p) {return p.get() == ptr;}) ; – Asik

0

std::list< boost::shared_ptr<T> > myList; 

boost::shared_ptr<T> tThisPtr = new T(); 

{ 
    myList.push_back(tThisPtr); 
} 

{ 
    myList.remove(tThisPtr);      
}