为什么标准关联有序容器允许 `const char*` 作为它们的键?

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

据我所知,我们不应该使用关系运算符比较两个 const 字符串 <>... 因为它比较的是地址而不是值:

const char* sz1 = "Hello";
const char* sz2 = "hello";
if(sz1 < sz2);// not valid. So use strcmp instead.

一切都很清楚,直到我创建了 const char*map, set 然后我得到的结果不正确:

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;

The default operator for the key is < operator.

这不是真的。非散列关联容器的默认比较运算符是 std::lessstd::less 使用 operator < 进行比较,但有一个关键的区别。不像内置的指针 operator < where

neither pointer is required to compare greater than the other.

source

std::less

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

所以这是一个安全的操作,我们可以可靠地在地图中存储指针。

正如其他人所指出的,也许有时您 想要 指针比较,如果您不这样做,那么容器允许您提供自己的自定义比较运算符,如下所示:

#include <cstring>
#include <iostream>
#include <iterator>
#include <string>
#include <set>

struct CStrCmp {
    bool operator() (const char* lhs, const char* rhs) const {
        return strcmp(lhs, rhs) < 0;
    }
};
int main()
{
    std::set<const char*, CStrCmp> scp{ "Hello", "World", "C++", "Programming" };
    std::set<std::string> sstr{ "Hello", "World", "C++", "Programming" };

    // This works too now
    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;
}