C ++映射访问丢弃限定符(const)


113

以下代码说,将map传递constoperator[]方法中会舍弃限定符:

#include <iostream>
#include <map>
#include <string>

using namespace std;

class MapWrapper {
public:
    const int &get_value(const int &key) const {
        return _map[key];
    }

private:
    map<int, int> _map;
};

int main() {
    MapWrapper mw;
    cout << mw.get_value(42) << endl;
    return 0;
}

这是因为在地图访问中可能进行分配吗?不能将具有地图访问权限的函数声明为const?

MapWrapper.cpp:10: error: passing ‘const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >’ as ‘this’ argument of ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = int, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, int> >]’ discards qualifiers


只是一个nitpick,但是mw可以简单地声明为MapWrapper mw;
路加福音

好点-我用几种语言写,所以我倾向于规范它们之间的语法,以便它们都适合我的脑海。:)
cdleary

我会很感激。但是要小心,在这种情况下,您不必进行额外的对象构造和分配。
路加福音

另一个好处-依赖默认赋值运算符在公共示例中不是一个好习惯。;)
cdleary

Answers:


152

std::mapoperator []未声明为const,不能因自己的行为:

T&运算符[](const键和键)

返回对该值的引用,该值映射到与键等效的键,如果尚不存在则执行插入。

结果,无法声明您的函数const,而使用地图的operator[]

std::mapfind()功能可让您查找键而无需修改地图。

find()传回iteratorconst_iteratorstd::pair同时包含键(.first)和值(.second)的。

在C ++ 11中,您也可以使用at()for std::map。与相比,如果element不存在,则该函数将引发std::out_of_range异常operator []


8
另外:VALUE = map.find(KEY)-> second; 我必须学习'find()'返回一个迭代器,它是pair类型的。
FlipMcF

5
我现在将在C11中添加您可以使用:std :: map :: at(key)并避免使用迭代器。
Juan Besa 2013年

3
有趣。我认为C ++可以区分左值operator[](例如foo[bar] = baz)和右值operator[](例如x = foo[bar]),后者肯定可以是const。
克劳迪(Claudiu)2014年

15

由于operator[]没有const限定的重载,因此不能在const限定的函数中安全地使用它。这可能是因为当前的过载是为了返回和设置键值而建立的。

相反,您可以使用:

VALUE = map.find(KEY)->second;

或者,在C ++ 11中,您可以使用at()运算符:

VALUE = map.at(KEY);

map.find(KEY)->second; 当映射值是字符串时是不安全的。当找不到KEY时,它倾向于打印垃圾。
syam

1
正确地解释了这一点。昨天,我花了2个小时试图弄清楚类似案件的情况。我们是否可以同意错误消息充其量是误导性的?如果它不包含单词'this'并引用const-ness而不是更通用的限定词,我会更加清楚。
carnicer

11

您不能operator[]在地图上使用,const因为该方法不是,const因为它允许您修改地图(您可以分配给_map[key])。尝试改用该find方法。


1
通过解释的方式:如果键不存在,map的operator []应该怎么做?如果映射为非常量,则将键添加为默认构造的值。如果映射常量,operator []可以返回什么?该键没有任何价值。

正确地解释了这一点。昨天,我花了2个小时试图弄清楚类似案件的情况。我们是否可以同意错误消息充其量是误导性的?如果它不包含单词'this'并引用const-ness而不是更通用的限定词,我会更加清楚。
carnicer

7

一些较新版本的GCC标头(在我的计算机上为4.1和4.2)具有非标准成员函数map :: at(),它们声明为const,如果密钥不在映射中,则抛出std :: out_of_range。

const mapped_type& at(const key_type& __k) const

从函数注释中的引用来看,似乎已建议将此作为标准库中的新成员函数。


我想这有点古怪。at函数是即将到来的标准的一部分,但是我发现在当前标准中没有at()。
塞巴斯蒂安·马赫

“ at”是C ++ 11的一部分。
艾蒂安

0

首先,您不应使用以_开头的符号,因为它们保留给语言实现/编译器编写者。_map在某人的编译器上成为语法错误非常容易,并且除了您自己之外,您没有人要责怪。

如果要使用下划线,请将其放在结尾,而不是开头。您可能会犯此错误,因为您看到了一些Microsoft代码。请记住,他们编写了自己的编译器,所以他们也许可以摆脱它。即使这样,这也是一个坏主意。

运算符[]不仅返回引用,而且实际上在地图中创建条目。因此,您不仅获得了一种映射,如果没有映射,那么您正在创建一个。那不是你想要的。


5
您的观点_是错误的。保留以两个下划线(__example)开头的标识符或以一个下划线和大写字母(_Example)开头的标识符。 _example不保留。
伊桑(Ethan)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.