如何避免地图访问的常量投射?

How to avoid const cast for map access?

本文关键字:常量 何避免 地图 访问      更新时间:2023-10-16

我有以下问题:

std::map<A*,double> map;
void getColor(A const * obj){
double d = map[obj]; // does not compile wihtout const_cast<A*>(obj)
// do something
}

我有一个地图std::map(某处),它存储指向对象的指针A. 我有一个函数getColorA操作对象,因此将指向const A的指针作为输入。

getColor函数在不使用const_cast的情况下将无法编译。

const cast是一个设计问题,但是如果我不想const中制作键map我不知道如何规避它。

任何帮助表示赞赏。

这里有两种可能的情况:

  1. 该函数知道/期望地图中已存在obj,并且您使用[]是为了方便起见。

  2. 您正在使用[]充分发挥其潜力,即您希望它在地图上添加obj(如果还没有的话)。

在情况 2 中,getColor签名中出现错误。由于它可以潜在地将obj传递到存储为A*的地方,因此它只接受const A*是错误的。请注意,即使函数不修改对象本身,而是将其传递到可以修改的对象,它也实际上是间接修改它,因此应将其视为非const

在情况 1 中,这取决于您的C++版本。C++14 引入了find的模板重载以及std::map的相关成员函数,它采用Key相当的任何内容,而不仅仅是Key。因此,您可以像这样修改函数:

void getColor( A const * obj){
doubel d = map.find(obj)->second;
// do something
}

请注意,要使其正常工作,您还需要更改地图的类型以使用透明比较器:std::map<A*,double, std::less<>> map;(正如@Leon的答案首先指出的那样)。

如果您坚持使用 C++11 或更早,那么您就不走运了,您将不得不忍受const_cast。请注意,通过适当的注释,在这种情况下,const_cast是完全安全且可接受的(更不用说在不更改map类型的情况下继续前进的唯一方法)。同样,您应该使用findat而不是[],因为您不想插入到地图中。

如果您有能力切换到 C++14,那么您可以将映射配置为使用透明比较器(这将起作用,因为常量指针可以与非常量指针进行比较):

std::map<A*,double, std::less<>> map;
//                  ^^^^^^^^^^^
//                  enable transparent comparator on this map
void getColor( A const * obj){
auto it = map.find(obj);
assert(it != map.end());
double d = it->second;
// do something
}

请注意,您将不得不使用std::map::find()而不是std::map::operator[],因为后者没有透明版本。