【问题标题】:How to avoid const cast for map access?如何避免 const cast 进行地图访问?
【发布时间】:2023-03-27 14:22:01
【问题描述】:

我有以下问题:

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 的指针。 我有一个函数getColor,它操纵对象A,因此将指向const A 的指针作为输入。

如果不使用 const_cast,函数 getColor 将无法编译。

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

任何帮助表示赞赏。

【问题讨论】:

  • 出于好奇:您为什么不想将键设为 const?
  • 为什么你不想将密钥设为const A*
  • @Gonmator 我认为 C++14 在这里没有帮助
  • c++14有什么不同??
  • @Gabriel 透明/异构比较器。但正如我在链接的问题中指出的那样,这不适用于 map::at

标签: c++ c++11 c++14 stdmap


【解决方案1】:

这里有两种可能的情况:

  1. 该函数知道/预计obj 已经存在于地图中,并且您使用[] 是为了方便。

  2. 您正在使用 [] 以充分发挥其潜力,即您希望它将 obj 添加到地图中(如果尚未出现)。

在情况 2 中,getColor 签名中有错误。由于它可能会将obj 传递到将其存储为A* 的位置,因此仅接受const A* 是错误的。请注意,即使函数没有修改对象自身,而是将其传递到可以修改的地方,它实际上是在间接修改它,因此应该将其视为非const

在情况 1 中,这取决于您的 C++ 版本。 C++14 引入了template overload of findstd::map 的相关成员函数,它采用任何与Key 相当的函数,而不仅仅是Key。因此,您可以像这样修改函数:

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

请注意,要使其正常工作,您还需要更改地图的类型以使用透明比较器:std::map&lt;A*,double, std::less&lt;&gt;&gt; map;(正如 @Leon's answer 首次指出的那样)。

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

【讨论】:

  • less&lt;&gt; 在传递指针时是否保证正确的事情?
  • @Yakk 是的,与operator &lt; 不同,std::less 保证即使对于指向不相关对象的指针也有效。
  • @angew "任何指针类型的特化都会产生一个总顺序,即使内置运算符&lt;&gt;&lt;=&gt;= 不会。对于模板特化greater&lt;void&gt;less&lt;void&gt;greater_equal&lt;void&gt;less_equal&lt;void&gt;,如果调用运算符调用内置运算符比较指针,则调用运算符产生一个总订单。”好的,标准到这里就清楚了!
  • @Yakk 有趣的事实:直到very recently,措辞实际上并不能保证它们所施加的总订单与内置或彼此施加的部分订单一致:)
【解决方案2】:

如果您能负担得起切换到 C++14 的费用,那么您可以将地图配置为使用 transparent comparator(这将起作用,因为可以将 const 指针与非 const 指针进行比较):

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[],因为后者是doesn't have a transparent version

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多