How can I use a std::map with std::weak_ptr as key?
-
07-07-2021 - |
سؤال
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
.)
المحلول
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.
نصائح أخرى
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.