简体   繁体   中英

Handling constness of pointed values in map keys

I have the following code:

#include <map>
using namespace std;
struct A {};

map</*const*/ A *, int> data;

int get_attached_value(const A *p) {
    return data.at(p);
}
void reset_all() {
    for (const auto &p : data) *p.first = A();
}

My problem is that this code fails on a type error both when I comment and uncomment the const in the type of data . Is there any way I can solve this without using const_cast and without losing the const in get_attached_value ?

The problem seems to be in the pointee type , which has to be the same in both pointer declarations (map key type and the get_attached_value 's argument).

OP's code uses const A* , which is a pointer to a const instance of class A (an alternative spelling is A const * ). Leaving this const in both map declaration and in get_attached_value ' argument almost works, but reset_all does not allow you to assign a new value to *p.first , because the resulting type is A const& (which cannot be assigned into).

Removing both consts works as well, but OP wants to keep a const in get_attached_value .

One solution for OP's requirements, keeping as many consts as possible, seems to be to change the pointer type to a const pointer to a non-const instance of A . This will keep reset_all working, while allowing to use a const pointer in both map declaration and get_attached_value 's argument:

#include <map>
using namespace std;
struct A {};

map<A * const, int> data;

int get_attached_value(A * const p) {
    return data.at(p);
}
void reset_all() {
    for (const auto &p : data)
        *p.first = A();
}

Another possible solution, with map's key as non-const but the get_attached_value 's parameter const, could use std::lower_bound with a custom comparator to replace the data.at() call:

#include <map>
#include <algorithm>

using namespace std;
struct A {};

map<A*, int> data;

int get_attached_value(A const * const p) {
    auto it = std::lower_bound(data.begin(), data.end(), p,
        [] (const std::pair<A* const, int>& a, A const* const b) {
            return a.first < b;
        }
    );
    return it->second;
}
void reset_all() {
    for (const auto &p : data)
        *p.first = A();
}

However, this solution will be significantly less efficient than one that would use map 's native search functions - std::lower_bound uses linear search when input iterators are not random access .

To conclude, the most efficient solution in C++11 or lower would probably use a const pointer as the map's key, and a const_cast in the reset_all function.

A bit more reading about const notation and pointers can be found here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM