简体   繁体   English

如何通过非const指针键在地图中找到const指针键

[英]How to find by a const pointer key in a map with non-const pointer keys

The following C++ code does not compile because it's passing a non-const pointer to a find() function which expects a const pointer. 以下C ++代码无法编译,因为它将非const指针传递给需要const指针的find()函数。

#include <map>

std::map<int*, double> mymap;

double myfind(const int * mykey)
{
    return mymap.find(mykey)->second;
}

Is there a way how to make the finding work without changing the type of the map or making variable mykey non-const? 有没有办法如何在不改变地图类型或使变量mykey非const的情况下使查找工作? After all the function find() does not modify the pointed object, it just compares the pointers. 在所有函数find()不修改指向对象之后,它只是比较指针。

A key in a map is semantically immutable, all map operations that allow direct access to keys do that by const -qualifying the key type (eg value_type is defined as pair<const Key, T> ). 映射中的键在语义上是不可变的,所有允许直接访问键的映射操作都通过对键类型进行const限定来实现(例如, value_type被定义为pair<const Key, T> )。

In case of int* key type however you'd get a const pointer to non-const int ( int*const ), which isn't very nice (it still works, since only the pointer value is used as the key, but the semantics of immutability become diluted, which can lead to bugs). int* key类型的情况下,你会得到一个指向非const intint*const )的const指针,这不是很好(它仍然有效,因为只有指针用作键,但是不变性的语义被稀释,这可能导致错误)。

Instead of casting away constness, just change the map to map<const int*, double> . 而不是丢弃constness,只需将map更改为map<const int*, double>

Then it will work for const int* as well as int* keys. 然后它将适用于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
}

Try const_cast which allows you to change constness (or volatility) of variable. 尝试使用const_cast ,它允许你改变变量的常量(或波动性)。

#include <map>

std::map<int*, double> mymap;

double myfind(const int * mykey)
{
    return mymap.find(const_cast<int*>(mykey))->second;
}

I think I have found a solution, but it requires C++14 transparent comparators. 我想我找到了一个解决方案,但它需要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()
}

An excellent article about C++14 transparent comparators can be found here . 约C ++ 14个透明比较优异的制品可以找到这里 To be completely honest, by adding the comparator, the type of mymap slightly changed which I originally didn't want to, but it's the best solution I could find. 说实话,通过添加比较器, mymap的类型略有改变,这是我原本不想要的,但它是我能找到的最佳解决方案。

If C++14 is not available, there are at least two evils we can choose from. 如果C ++ 14不可用,我们可以选择至少两个邪恶。 The first one is to copy mymap to a new std::map<const int*, double> in myfind , which is horribly unefficient. 第一种是拷贝mymap到一个新std::map<const int*, double>myfind ,这是可怕的效率不高。 The second one is casting away constness by using a const_cast<int*>(mykey) which should be avoided if possible. 第二个是通过使用const_cast<int*>(mykey)const_cast<int*>(mykey) ,如果可能的话应该避免使用它。

You may have a const-correctness issue. 您可能有一个const正确性问题。 const int * may not be what you think it is . const int * 可能不是你想象的那样 It is a pointer to a constant integer . 它是一个指向常量整数指针 This is not the same as the key type of your map, which is a pointer to a (non-constant) integer . 这与地图的键类型不同,后者是指向(非常数)整数指针 And neither are the same as int * const which is a constant pointer to a (non-constant) integer . 并且它们都不是int * const ,它是一个指向(非常量)整数常量指针 The issue isn't whether the key value itself is mutable or immutable, it's whether the things you're storing pointers to are mutable or immutable. 问题不在于键值本身是可变的还是不可变的,而是存储指针的东西是可变的还是不可变的。

For example, this compiles: 例如,这编译:

std::map<int *, double> mymap;
double myfind(int * const mykey) {
    return mymap.find(mykey)->second;
}

As does this: 就像这样:

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;
}

Do you see the difference? 你看得到差别吗? In your original code, the compiler is quite right to flag an error. 在原始代码中,编译器标记错误是完全正确的。 If your function takes a const int * , then you are in effect promising not to modify the int pointed to by the pointer I pass in. But if you use such a pointer as int * in the key of a std::map , you may be allowing someone to modify that int . 如果你的函数采用const int * ,那么你实际上承诺不会修改我传入的指针所指向的int 。但是如果你在std::map的键中使用这样的指针作为int * ,那么你可能允许某人修改该int

In this particular case, we know that std::map::find() will not assign to a pointer argument, but the compiler doesn't, which is why const_cast<> exists as pointed out in other answers. 在这种特殊情况下,我们知道std::map::find()不会分配给指针参数,但编译器不会,这就是const_cast<>存在的原因,如其他答案中所指出的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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