2012-10-13 10 views
6

Mam pytanie dotyczące użycia std :: weak_ptr jako klucza do std :: map.std :: map z std :: weak_ptr key

#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; 
} 

Powyższy program nie budować i próbuje skompilować daje wiele komunikatów o błędach, takich jak:

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>   ] 

Problem występuje ze względu na następujący wiersz:

myMap[weakptr] = true; 

Błąd komunikaty wydają się być powiązane z operatorem <. Czy muszę zdefiniować operatora < dla weak_ptrs? Dokładnie to, co operatorzy muszą być zdefiniowane, aby użyć typ danych jako klucz do std :: map?

(Należy zauważyć, że już zdefiniowane == operatora w przestrzeni nazw std. Również mam zamiar użyć weak_ptr do niestandardowego typu klasy a nie int.)

Odpowiedz

13

C++ 11 zapewnia odpowiednie mechanizmy dla porównań std::weak_ptr, a mianowicie: std::owner_less.

Powinno to być domyślne dla map i zestawów. Jeśli kompilator C++, którego używasz, ma problemy, spróbuj użyć std::owner_less, jeśli jest dostępny. Jeśli nie jest dostępny, musisz podać podobny mechanizm, jak std::owner_less, aby odpowiednio porównać obiekty std::weak_ptr.

+4

Ostatecznym formularzem będzie 'std :: map , U, std :: owner_less >> – DiB

0

Trzeci argument szablonu do std :: map <> domyślnie std :: less, który zwykle po prostu wywołuje operatora <() dla klucza. Możesz więc zdefiniować operatora <() dla std :: weak_ptr <> (co jest prawdopodobnie złym pomysłem) lub po prostu utworzyć funktor i dostarczyć go jako trzeci argument szablonu dla std :: map <>.

Mimo to nie jestem pewien, czy to rzeczywiście działa, ponieważ std :: map <> oczekuje, że klucze będą niezmienne, podczas gdy std :: weak_ptr <> mogą się zmienić w dowolnym momencie (wartość wskaźnika może stać się pusta).

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(); 
    } 
}; 

Użyj tego na własne ryzyko. (Lub jakakolwiek jest ekspresja)

+0

Prawdopodobnie chodziło o 'operator()' nie 'operator <' w klasie komparatora. – PiotrNycz

+0

@ Piotrotrycz, tak dzięki za opowiadanie, to naprawię. – mauve