如何在具有非 const 指针键的映射中通过 const 指针键查找
How to find by a const pointer key in a map with non-const pointer keys
以下 C++ 代码无法编译,因为它正在将非常量指针传递给需要 const 指针的 find()
函数。
#include <map>
std::map<int*, double> mymap;
double myfind(const int * mykey)
{
return mymap.find(mykey)->second;
}
有没有办法在不更改地图类型或使变量 mykey
非常量的情况下使查找工作正常?
毕竟函数find()
不修改指向的对象,它只是比较指针。
尝试 const_cast
,它允许您更改变量的常量(或波动性)。
#include <map>
std::map<int*, double> mymap;
double myfind(const int * mykey)
{
return mymap.find(const_cast<int*>(mykey))->second;
}
映射中的键在语义上是不可变的,所有允许直接访问键的映射操作都是通过 const
限定键类型(例如 value_type
定义为 pair<const Key, T>
).
在 int*
键类型的情况下,你会得到一个指向非常量 int
(int*const
) 的 const
指针,这不是很好(它仍然有效,因为只有指针 value 被用作键,但不变性的语义被稀释,这可能导致错误)。
不要放弃常量,只需将 map
更改为 map<const int*, double>
。
那么它将适用于 const int*
以及 int*
键。
#include <map>
std::map<const int*, double> mymap;
double myfind(const int * mykey)
{
return mymap.find(mykey)->second; // just works
}
double myfind(int * mykey)
{
return mymap.find(mykey)->second; // also works
}
您可能遇到常量正确性问题。 const int *
may not be what you think it is。它是一个 指向 常数 整数 的指针。这与地图的键类型不同,后者是 指向(非常量)整数 的指针。两者都与 int * const
不同,后者是指向(非常量)整数 的 常量指针。问题不在于键值本身是可变的还是不可变的,而是你存储指针的东西是可变的还是不可变的。
例如这样编译:
std::map<int *, double> mymap;
double myfind(int * const mykey) {
return mymap.find(mykey)->second;
}
这样做:
std::map<const int *, double> mymap;
double myfind(const int *mykey) {
return mymap.find(mykey)->second;
}
double myfind2(const int * const mykey) {
return mymap.find(mykey)->second;
}
你看出区别了吗?在您的原始代码中,编译器非常适合标记错误。如果您的函数采用 const int *
,那么您实际上承诺不会修改我传入的指针所指向的 int
。但是如果您在std::map
的键,您可能允许某人修改 int
。
在这种特殊情况下,我们知道 std::map::find()
不会分配给指针参数,但编译器不会,这就是其他答案中指出的 const_cast<>
存在的原因。
我想我找到了解决方案,但它需要 C++14 透明比较器。
#include <map>
#include <iostream>
struct CompareIntPtrs
{
using is_transparent = void; // enabling C++14 transparent comparators
bool operator()(const int * l, const int * r) const
{
return l < r;
}
};
std::map<int*, double, CompareIntPtrs> mymap;
double myfind(const int * key)
{
return mymap.find(key)->second;
}
int main()
{
int x {6};
mymap[&x] = 66; // inserting to the map
const int * px = &x; // creating a "const int *" variable
std::cout << myfind(px) << std::endl; // using "const int *" for finding in map with "int*" keys
std::cout << mymap.find(px)->second << std::endl; // we could even skip using myfind()
}
可以找到一篇关于 C++14 透明比较器的优秀文章 here。
老实说,通过添加比较器,mymap
的类型略有改变,我原本不想这样做,但这是我能找到的最好的解决方案。
如果C++14不可用,我们至少有两种选择。
第一个是将 mymap
复制到 myfind
中的新 std::map<const int*, double>
,这是非常低效的。
第二个是通过使用 const_cast<int*>(mykey)
来摆脱 constness,如果可能的话应该是 avoided。
以下 C++ 代码无法编译,因为它正在将非常量指针传递给需要 const 指针的 find()
函数。
#include <map>
std::map<int*, double> mymap;
double myfind(const int * mykey)
{
return mymap.find(mykey)->second;
}
有没有办法在不更改地图类型或使变量 mykey
非常量的情况下使查找工作正常?
毕竟函数find()
不修改指向的对象,它只是比较指针。
尝试 const_cast
,它允许您更改变量的常量(或波动性)。
#include <map>
std::map<int*, double> mymap;
double myfind(const int * mykey)
{
return mymap.find(const_cast<int*>(mykey))->second;
}
映射中的键在语义上是不可变的,所有允许直接访问键的映射操作都是通过 const
限定键类型(例如 value_type
定义为 pair<const Key, T>
).
在 int*
键类型的情况下,你会得到一个指向非常量 int
(int*const
) 的 const
指针,这不是很好(它仍然有效,因为只有指针 value 被用作键,但不变性的语义被稀释,这可能导致错误)。
不要放弃常量,只需将 map
更改为 map<const int*, double>
。
那么它将适用于 const int*
以及 int*
键。
#include <map>
std::map<const int*, double> mymap;
double myfind(const int * mykey)
{
return mymap.find(mykey)->second; // just works
}
double myfind(int * mykey)
{
return mymap.find(mykey)->second; // also works
}
您可能遇到常量正确性问题。 const int *
may not be what you think it is。它是一个 指向 常数 整数 的指针。这与地图的键类型不同,后者是 指向(非常量)整数 的指针。两者都与 int * const
不同,后者是指向(非常量)整数 的 常量指针。问题不在于键值本身是可变的还是不可变的,而是你存储指针的东西是可变的还是不可变的。
例如这样编译:
std::map<int *, double> mymap;
double myfind(int * const mykey) {
return mymap.find(mykey)->second;
}
这样做:
std::map<const int *, double> mymap;
double myfind(const int *mykey) {
return mymap.find(mykey)->second;
}
double myfind2(const int * const mykey) {
return mymap.find(mykey)->second;
}
你看出区别了吗?在您的原始代码中,编译器非常适合标记错误。如果您的函数采用 const int *
,那么您实际上承诺不会修改我传入的指针所指向的 int
。但是如果您在std::map
的键,您可能允许某人修改 int
。
在这种特殊情况下,我们知道 std::map::find()
不会分配给指针参数,但编译器不会,这就是其他答案中指出的 const_cast<>
存在的原因。
我想我找到了解决方案,但它需要 C++14 透明比较器。
#include <map>
#include <iostream>
struct CompareIntPtrs
{
using is_transparent = void; // enabling C++14 transparent comparators
bool operator()(const int * l, const int * r) const
{
return l < r;
}
};
std::map<int*, double, CompareIntPtrs> mymap;
double myfind(const int * key)
{
return mymap.find(key)->second;
}
int main()
{
int x {6};
mymap[&x] = 66; // inserting to the map
const int * px = &x; // creating a "const int *" variable
std::cout << myfind(px) << std::endl; // using "const int *" for finding in map with "int*" keys
std::cout << mymap.find(px)->second << std::endl; // we could even skip using myfind()
}
可以找到一篇关于 C++14 透明比较器的优秀文章 here。
老实说,通过添加比较器,mymap
的类型略有改变,我原本不想这样做,但这是我能找到的最好的解决方案。
如果C++14不可用,我们至少有两种选择。
第一个是将 mymap
复制到 myfind
中的新 std::map<const int*, double>
,这是非常低效的。
第二个是通过使用 const_cast<int*>(mykey)
来摆脱 constness,如果可能的话应该是 avoided。