There can be a performance downside when using associative_container<T, less<>>
: Consider a type like
#include <iostream>
#include <set>
#include <string>
struct stupid_string
{
stupid_string(char const* s)
: s(s)
{ std::cout << "copy\n"; }
stupid_string(char const* s, int) // silent
: s(s)
{}
friend bool operator<(stupid_string const& lhs, stupid_string const& rhs);
private:
std::string s;
};
bool operator<(stupid_string const& lhs, stupid_string const& rhs) {
return lhs.s < rhs.s;
}
int main() {
std::set<stupid_string, std::less<>> s;
s.emplace("hello", 0);
s.emplace("world", 0);
s.emplace("foobar", 0);
std::cout << "find\n";
(void)s.find("test");
}
Here, the application of operator<
in the algorithm performed by s.find
will convert the character literal to a stupid_string
implicitly. This happens for each comparison performed! Live demo
I know of one case where something similar happened in production code, with a non-conforming C++03 StdLib implementation.
This is by the way the main reason why heterogeneous lookup via less<>
was made opt-in; see N3657:
Stephan T. Lavavej suggested that the two problems of preserving
existing behaviour and allowing heterogeneous lookups could both be
solved by making the containers detect when the comparison object
accepts heterogeneous arguments and only conditionally overloading the
current lookup functions with template versions.
less<>
andless<T>
. – Manometerstring_view
is not in C++14 – Ethelynethene