为什么标准关联有序容器允许 `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.
- 我注意到像
map, multimap, set, multiset
这样的有序关联容器对其 key
施加了限制,因此应该如何比较键以对容器中的元素进行排序。键的默认运算符是 <
operator.
一切都很清楚,直到我创建了 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
比较字符串指针,而 sstr
只要 class string
定义了 [=15] 就可以=] 才能正常工作。
为什么STL允许这样做? (创建关键元素类型为 char*
的关联容器)以及为什么这里甚至没有警告?
The default operator for the key is <
operator.
这不是真的。非散列关联容器的默认比较运算符是 std::less
。 std::less
使用 operator <
进行比较,但有一个关键的区别。不像内置的指针 operator <
where
neither pointer is required to compare greater than the other.
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 <
, >
, <=
, >=
.
所以这是一个安全的操作,我们可以可靠地在地图中存储指针。
正如其他人所指出的,也许有时您 想要 指针比较,如果您不这样做,那么容器允许您提供自己的自定义比较运算符,如下所示:
#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;
}
据我所知,我们不应该使用关系运算符比较两个 const 字符串 <>
... 因为它比较的是地址而不是值:
const char* sz1 = "Hello";
const char* sz2 = "hello";
if(sz1 < sz2);// not valid. So use strcmp instead.
- 我注意到像
map, multimap, set, multiset
这样的有序关联容器对其key
施加了限制,因此应该如何比较键以对容器中的元素进行排序。键的默认运算符是<
operator.
一切都很清楚,直到我创建了 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
比较字符串指针,而sstr
只要 classstring
定义了 [=15] 就可以=] 才能正常工作。为什么STL允许这样做? (创建关键元素类型为
char*
的关联容器)以及为什么这里甚至没有警告?
The default operator for the key is
<
operator.
这不是真的。非散列关联容器的默认比较运算符是 std::less
。 std::less
使用 operator <
进行比较,但有一个关键的区别。不像内置的指针 operator <
where
neither pointer is required to compare greater than the other.
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
<
,>
,<=
,>=
.
所以这是一个安全的操作,我们可以可靠地在地图中存储指针。
正如其他人所指出的,也许有时您 想要 指针比较,如果您不这样做,那么容器允许您提供自己的自定义比较运算符,如下所示:
#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;
}