2012-10-13 6 views
6

Ho una domanda sull'utilizzo di std :: weak_ptr come chiave per una std :: map.std :: map con std :: chiave weak_ptr

#include <map> 
#include <memory> 

int main() 
{ 
std::map< std::weak_ptr<int>, bool > myMap; 

std::shared_ptr<int> sharedptr(new int(5)); 
std::weak_ptr<int> weakptr = sharedptr; 

myMap[weakptr] = true; 

return 0; 
} 

Il programma di cui sopra non costruire e cercando di compilare dà molti messaggi di errore come ad esempio:

1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfunctional(125): error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const std::tr1::weak_ptr<_Ty>' 
1>   with 
1>   [ 
1>    _Ty=int 
1>   ] 
1>   C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xtree(1885) : see declaration of 'std::operator <' 
1>   C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfunctional(124) : while compiling class template member function 'bool std::less<_Ty>::operator()(const _Ty &,const _Ty &) const' 
1>   with 
1>   [ 
1>    _Ty=std::tr1::weak_ptr<int> 
1>   ] 
1>   C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\map(71) : see reference to class template instantiation 'std::less<_Ty>' being compiled 
1>   with 
1>   [ 
1>    _Ty=std::tr1::weak_ptr<int> 
1>   ] 
1>   C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xtree(451) : see reference to class template instantiation 'std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,_Mfl>' being compiled 
1>   with 
1>   [ 
1>    _Kty=std::tr1::weak_ptr<int>, 
1>    _Ty=bool, 
1>    _Pr=std::less<std::tr1::weak_ptr<int>>, 
1>    _Alloc=std::allocator<std::pair<const std::tr1::weak_ptr<int>,bool>>, 
1>    _Mfl=false 
1>   ] 

Il problema si verifica a causa della seguente riga:

myMap[weakptr] = true; 

L'errore i messaggi sembrano essere correlati all'operatore <. Devo definire l'operatore < per weak_ptrs? Esattamente ciò che gli operatori devono essere definiti per utilizzare un tipo di dati come chiave per una std :: map?

(Vorrei sottolineare che ho già definito operatore == nel namespace std. Inoltre, ho intenzione di usare un weak_ptr a un tipo classe personalizzata e non un int.)

risposta

13

C++ 11 fornisce meccanismi appropriati per il confronto di std::weak_ptr, vale a dire: std::owner_less.

Questo dovrebbe essere il valore predefinito per mappe e set. Se il compilatore C++ che stai utilizzando sta avendo difficoltà, prova a utilizzare std::owner_less se disponibile. Se non è disponibile, è necessario fornire un meccanismo simile a std::owner_less in modo da poter confrontare opportunamente gli oggetti std::weak_ptr.

+4

La forma finale sarebbe 'std :: map , U, std :: owner_less >>' – DiB

0

Il terzo argomento modello a std :: mappa <> predefinito per std :: less che di solito chiama semplicemente operatore <() per Chiave. Quindi puoi definire l'operatore <() per std :: weak_ptr <> (che è probabilmente una cattiva idea) o semplicemente creare un functor e fornirlo come terzo argomento template per std :: map <>.

Anche così io sono sicuro se questo può effettivamente lavorare perché std :: map <> si aspetta che le chiavi siano immutabili, mentre std :: weak_ptr <> 's possono cambiare in qualsiasi momento (il valore del puntatore può diventare nullo).

struct WeakPtrLess 
{ 
    template <typename T> 
    bool operator() (const std::weak_ptr<T>& l, const std::weak_ptr<T>& r) const 
    { 
    std::shared_ptr<T> sl = l.lock(); 
    std::shared_ptr<T> sr = r.lock(); 

    return sl.get() < sr.get(); 
    } 
}; 

Utilizzare a proprio rischio e pericolo. (O qualunque sia l'espressione)

+0

Probabilmente intendevi 'operator()' non 'operatore <' nella classe di confronto. – PiotrNycz

+0

@PiotrNycz, sì grazie per avermelo detto, lo aggiusterò. – mauve