I have a std::map
with shared_ptr<T>
keys, and I need it to use the actual value (of type T
, i.e. *key
) for lookups, not the value of the shared pointer itself.
I know I can write my own custom comparator (as I've done below), but I was wondering if the STL supplies a comparator specifically for this purpose.
To demonstrate what I'm talking about, I created this simple example that uses a std::set
of strings (I've also put it on GitHub as a gist):
#include <set>
#include <string>
#include <memory>
#include <iostream>
#include <functional>
template< typename T >
struct shared_ptr_comparator {
bool operator()(const std::shared_ptr<T> &a, const std::shared_ptr<T> &b) const {
return std::less<T>()(*a, *b);
}
};
void ptr_set_with_custom_comparator() {
std::set< std::shared_ptr<std::string>, shared_ptr_comparator<std::string> > ptr_set;
ptr_set.insert(std::make_shared<std::string>("world"));
ptr_set.insert(std::make_shared<std::string>("hello"));
ptr_set.insert(std::make_shared<std::string>("abc"));
for(auto const& entry : ptr_set) {
std::cout << *entry << std::endl;
}
}
void ptr_set_with_owner_less() {
std::set< std::shared_ptr<std::string>, std::owner_less<std::shared_ptr<std::string>> > ptr_set;
ptr_set.insert(std::make_shared<std::string>("world"));
ptr_set.insert(std::make_shared<std::string>("hello"));
ptr_set.insert(std::make_shared<std::string>("abc"));
for(auto const& entry : ptr_set) {
std::cout << *entry << std::endl;
}
}
void raw_set() {
std::set<std::string> raw_set;
raw_set.insert("world");
raw_set.insert("hello");
raw_set.insert("abc");
for(auto const& entry : raw_set) {
std::cout << entry << std::endl;
}
}
int main() {
std::cout << "A basic set of strings:" << std::endl;
raw_set();
std::cout << std::endl;
std::cout << "A set of shared_ptr<string>s with owner_less as the comparator:" << std::endl;
ptr_set_with_owner_less();
std::cout << std::endl;
std::cout << "A set of shared_ptr<string>s with the comparator shared_ptr_comparator:" << std::endl;
ptr_set_with_custom_comparator();
return 0;
}
The code above can be complied with clang++ -Wall -std=c++11
. Here's the output:
A basic set of strings:
abc
hello
world
A set of shared_ptr<string>s with owner_less as the comparator:
world
hello
abc
A set of shared_ptr<string>s with the comparator shared_ptr_comparator:
abc
hello
world
Here, a sorted ordering when iterating and printing the contents std::set
implies that the _actual underlying values) are being compared. A quick overview of the example above:
The function
raw_set
just usesset<string>
(doesn't useshared_ptr
), and is present for reference.I am able to achieve what I want with my hand-written
shared_ptr_comparator
. The functionptr_set_with_custom_comparator
which utilizes it, works as expected.The function
ptr_set_with_owner_less
did not work as expected. Doesowner_less
(orowner_before
) rely on the addresses/values of the pointers themselves?
I have two questions:
Does anything equivalent to
shared_ptr_comparator
(defined in the program above), exist in the STL? I ask because the comparator I wrote seems like a really common use case, and I would be very surprised if the STL didn't have anything equivalent to it.What exactly does owner_less and owner_before (which it calls) do? Do they simply check for equivalence of the underlying pointers? I'm not sure if I'm using it right.
Thanks in advance for any answers to this question.