Question

How can I use std::weak_ptr as key for a std::map as shown in the following code?

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

The above program doesn't build and trying to compile it gives many error messages such as:

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

The problem occurs due to the following line:

myMap[weakptr] = true;

The error messages seem to be related to operator<. Do I need to define operator< for weak_ptr? Exactly, what operators need to be defined in order to use a data type as a key for a std::map?

(I should note that I have already defined operator== in the std namespace. Also, I plan to use a weak_ptr to a custom class type and not an int.)

Was it helpful?

Solution

C++11 provides appropriate mechanisms for comparisons of std::weak_ptr, namely: std::owner_less.

This should be the default for maps and sets. If the C++ compiler you are using is having a hard time, try using std::owner_less if it is available. If it is not available, you will need to provide a similar mechanism as std::owner_less so you can appropriately compare std::weak_ptr objects.

OTHER TIPS

As explained in Jody Hagins' answer, you should use std::owner_less as comparison function object of an associative container if you use a std::weak_ptr as key. I'd like to expand on that answer by providing the following full solution for your code:

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

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

    myMap[weakptr] = true;

    return 0;
}

Since C++17 you can omit the template parameter for owner_less, resulting in shorter code as follows:

std::map<std::weak_ptr<int>, bool, std::owner_less<>> myMap;

And if you plan to use a weak_ptr to a custom class instead of an int, then you can simply replace the int by the name of your class as shown in this example code on Coliru.

In general, apart from providing a proper comparison function (or overloading operator<) for a (custom) key type, nothing needs to be done for a std::map. Overloading operator== for the key type is not required.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top