Gabriel Gabriel - 15 days ago 8
C++ Question

How to avoid const cast for map access?

I have the following issue:

std::map<A*,double> map;

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


I have a map
std::map
(somewhere) which stores pointers to objects
A
.
I have a function
getColor
which does not manipulate objects
A
and so takes a pointer to a
const A
as input.

The function
getColor
will not compile without using a const_cast.

Const cast is a design issue, but I dont know how to circumenvent it, if I dont want to make the keys in
map
const.

Any help appreciated.

Answer

There's two possible scenarios here:

  1. The function knows/expects that obj is already present in the map, and you're using [] for convenience.

  2. You're using [] for its full potential, i.e. you expect it to add obj to the map if not already there.

In situation 2, you have an error in the getColor signature. Since it can potentially pass obj to a place where it will be stored as A*, it is wrong for it to accept a const A* only. Note that even if a function doesn't modify an object itself but passes it on somewhere where it can be modified, it is effectively modifying it indirectly and should therefore take it as non-const.

In situation 1, it depends on your C++ version. C++14 introduced a template overload of find and related member functions of std::map which takes anything comparable with Key instead of only Key. You could therefore modify the function like this:

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

Note that for this to work, you also need to change the map's type to use a transparent comparator: std::map<A*,double, std::less<>> map; (as first pointed out by @Leon's answer).

If you're stuck with C++11 or earlier, you're out of luck and you'll have to live with the const_cast. Note that with a suitable comment, a const_cast is perfectly safe and acceptable in this case (not to mention the only way to proceed without changing the type of map). Again, you should use find or perhaps at instead of [], since you do not want to insert into the map.