为什么标准关联有序容器允许"const char*"作为其键?

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

本文关键字:quot char const 标准 关联 为什么      更新时间:2023-10-16

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

const char* sz1 = "Hello";
const char* sz2 = "hello";
if(sz1 < sz2);// not valid. So use strcmp instead.
  • 我注意到像map, multimap, set, multiset这样的有序关联容器对其key施加了限制,以便应该将键与容器中的元素进行排序进行比较。键的默认运算符是<运算符。

一切都很清楚,直到我创建了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;
  • 很明显,scp比较字符串的指针,而只要类string定义了正常工作<sstr就可以了。

  • 为什么STL允许这样做?(创建关键元素类型为char*的关联容器(为什么这里甚至没有警告?

键的默认运算符是<运算符。

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

两个指针都不需要大于另一个指针。

std::less

任何指针类型的专用化都会产生一个严格的总顺序,该顺序在这些专用化之间是一致的,并且也与内置运算符<><=>=强加的偏序一致。

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

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

#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;
}