【问题标题】:C++ map access discards qualifiers (const)C++ 映射访问丢弃限定符 (const)
【发布时间】:2021-01-15 01:32:42
【问题描述】:

以下代码表示将映射作为const 传递给operator[] 方法会丢弃限定符:

#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

【问题讨论】:

  • 只是吹毛求疵,但 mw 可以简单地声明为 MapWrapper mw;
  • 好点——我用几种语言写作,所以我倾向于规范它们的语法,这样它们都适合我的脑海。 :)
  • 我很感激。不过要小心,在这种情况下,您有一个不必要的额外对象构造和分配。
  • 另一个好点——依赖默认赋值运算符对于公共示例来说不是一个好习惯。 ;)

标签: c++ stl constants maps


【解决方案1】:

std::map's operator [] is not declared as const, and cannot be due to its behavior:

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

返回对映射到与 key 等效的 key 的 value 的引用,如果这样的 key 不存在,则执行插入。

因此,您的函数无法声明为const,而使用映射的operator[]

std::map's find() 功能可以让您在不修改地图的情况下查找密钥。

find()iteratorconst_iterator 返回到包含键 (.first) 和值 (.second) 的 std::pair

在 C++11 中,您还可以将at() 用于std::map。如果元素不存在,则函数会抛出 std::out_of_range 异常,与 operator [] 不同。

【讨论】:

  • 另外:VALUE = map.find(KEY)->second;我必须知道 'find()' 返回一个迭代器,它是对类型的。
  • 我要补充一点,现在在 C11 中您可以使用:std::map::at(key) 并避免使用迭代器。
  • 有趣。我认为 C++ 会区分左值operator[](例如foo[bar] = baz)和右值operator[](例如x = foo[bar])——后者当然可以是const。
【解决方案2】:

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

相反,您可以使用:

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

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

VALUE = map.at(KEY);

【讨论】:

  • map.find(KEY)-&gt;second; 在映射值是字符串时是不安全的。当找不到 KEY 时,它往往会打印垃圾。
  • 这是一个正确解释的答案。昨天我花了 2 个小时试图弄清楚类似案例的情况。我们是否可以同意错误信息充其量是误导性的?如果它没有“this”这个词并引用 const-ness 而不是更通用的 qualifier,我可能会更清楚。
【解决方案3】:

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

【讨论】:

  • 顺便解释一下:如果key不存在,map的operator[]怎么办?如果映射是非常量的,则使用默认构造值添加键。如果 map 是 const,operator[] 可以返回什么?该键没有任何价值。
  • 这是一个正确解释的答案。昨天我花了 2 个小时试图弄清楚类似案例的情况。我们是否可以同意错误信息充其量是误导性的?如果它没有“this”这个词并引用 const-ness 而不是更通用的 qualifier,我可能会更清楚。
【解决方案4】:

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

const mapped_type& at(const key_type& __k) const

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

【讨论】:

  • 我想这有点怪癖。 at-function 是即将发布的标准的一部分,但我在当前的标准中找不到 at()。
  • 'at' 是 C++11 的一部分。
【解决方案5】:

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

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

运算符 [] 不仅返回一个引用,它实际上在映射中创建条目。所以你不只是得到一个映射,如果没有,你正在创建一个。这不是你想要的。

【讨论】:

  • 您关于_ 的观点是错误的。以两个下划线 (__example) 开头的标识符或以一个下划线和一个大写字母 (_Example) 开头的标识符被保留。 _example 未保留。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-07
  • 1970-01-01
相关资源
最近更新 更多