一、char*与string不一样!
1、例1:
std::map<std::string, int> my_map;
map.insert(pair<std::string, int>("hello", 1));
cout << "my_map_value = " << my_map["hello"] << endl;
结果:1.
对于这个结果,大家并不会感到意外,因为在C++中,std::map
的键类型必须是可比较的,也就是说,它们必须能够使用比较运算符(如 <
)进行排序。而std::string
对象可以正确地比较其内容,因此使用 std::map<std::string, int>
将允许你使用字符串字面量并确保它们被视为相同的键。
2、例2:
std::map<char*, int>my_map;
char str1[] = {(char*)"hello"};
my_map.insert(pair<char*, int>(str1, 1));
cout << "my_map_value1 = " << my_map["hello"] << endl;
cout << "my_map_value2 = " << my_map[str1] << endl;
结果:my_map_value1 = x(一个未知的数)
my_map_value2 = 1
这个结果意不意外,最开始我使用map的时候,因为明确不使用string,因此使用了char*作为键的类型。但是对于原始的 char*
类型,这些指针之间的比较实际上是基于它们在内存中的地址值,而不是它们所指向的字符串内容。这意味着即使两个 char*
指向完全相同的字符串内容,只要它们的地址不同,它们就会被视为不同的键。
当你尝试在 std::map<char*, int>
中使用 []
运算符时,如果传递的是一个字符串字面量,例如 "key"
,这实际上会被转换为一个临时的 const char*
对象。每次调用 []
运算符时,都会创建一个新的临时 const char*
,这意味着即使你传递了看似相同的字符串字面量,每次也会得到一个不同的指针,因此每次都会创建一个新的键条目,而不是更新已存在的键。
为了避免这种问题,有几种解决方案:
-
使用
std::string
作为键:std::string
对象可以正确地比较其内容,因此使用std::map<std::string, int>
将允许你使用字符串字面量并确保它们被视为相同的键。 -
使用自定义比较器: 你可以为
std::map
提供一个自定义的比较函数或比较对象,该函数将比较char*
所指向的字符串内容,而不是它们的地址。这样,即使char*
的地址不同,但只要它们指向相同的字符串,它们就会被视为相等的键。
以下是GPT中的一个例子,大家可以参考下
// 定义一个比较结构体,用于比较两个const char*类型的字符串
struct Compare {
// 重载比较运算符,返回lhs和rhs比较的结果,如果lhs小于rhs则返回true
bool operator()(const char* lhs, const char* rhs) const {
// 使用标准库函数strcmp比较两个字符串,如果lhs小于rhs,strcmp返回负数,因此结果为真
return std::strcmp(lhs, rhs) < 0;
}
};
int main() {
// 使用Compare作为比较器,创建一个map,其中键是const char*类型,值是int类型
std::map<const char*, int, Compare> m;
// 使用字符串字面量"foo"作为键,插入值1到map中
m["foo"] = 1;
// 再次使用字符串字面量"foo"作为键,这次插入值2,由于键相同(根据Compare比较器),值会被更新为2
m["foo"] = 2;
// 输出map的大小,应为1,因为"foo"键只对应一个元素
std::cout << "Size of map: " << m.size() << std::endl; // 输出: 1
return 0;
}
当map中传入第三个参数Compare后,在例2中, my_map_value1的值可以返回1,因为重写了比较器,通过比较字符串的内容来将char*与字符串常量视为相等的键,从而获得相同的值。
总之,在 std::map
中使用 char*
作为键时要小心,因为它可能会导致意外的结果,除非你采取措施确保键的正确比较。