Search code examples
c++stlstdmapstdset

Why do standard associative ordered containers allow `const char*` as their key?


As far as I know we should never compare two const character strings using relational operators <>... because the fact that it compares the addresses rather than the values:

const char* sz1 = "Hello";
const char* sz2 = "hello";
if(sz1 < sz2);// not valid. So use strcmp instead.
  • What I've noticed that Ordered Associative Containers like map, multimap, set, multiset impose a restriction on their key so that the key should some how be compared to order the elements in the container. The default operator for the key is < operator.

Everything is clear until I've created a map, set of const char* then I get the results incorrect:

std::set<const char*> scp{ "Hello", "World", "C++", "Programming" };    
std::set<std::string> sstr{ "Hello", "World", "C++", "Programming" };

// error
std::copy(scp.cbegin(), scp.cend(), std::ostream_iterator<const char*>(std::cout, " "));
std::cout << std::endl;

// Ok 
std::copy(sstr.cbegin(), sstr.cend(), std::ostream_iterator<std::string>(std::cout, " "));
std::cout << std::endl;
  • It is apparent that scp compares pointers to character strings while sstr is Ok as long as class string has defined < to work properly.

  • Why STL allows this? (creating associative containers whose key element type is a char*) and why here's even no warning?


Solution

  • The default operator for the key is < operator.

    This is not true. The default comparison operator for the non-hashed associative containers is std::less. std::less uses operator < for comparisons, but with one key difference. Unlike the pointers built in operator < where

    neither pointer is required to compare greater than the other.

    source

    std::less has that the

    specializations for any pointer type yield a strict total order that is consistent among those specializations and is also consistent with the partial order imposed by the built-in operators <, >, <=, >=.

    source

    So this is a safe operation and we can reliably store pointers in the map.