为什么我不能使用 std::map[ ] 添加字符串,但 std::map.at() 有效?

Why I can't use the std::map[ ] to add a string, but std::map.at() works?

我的问题是为什么 s += t.getM()[0];在示例代码中 raise

main.cpp:44:20: error: passing ‘const std::map >’ as ‘this’ argument discards qualifiers [-fpermissive]

我检查了 cppreference,它说 return 都是参考。

此外,为什么 operator[] 和 .at() 都适用于 std::vector?

示例代码在这里。

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

using namespace std;

class test {
    public:
        test(string str) {
            vec.push_back(str);
            mp[0] = str;
            
        }   
        
        const vector<string>& getV() const {
            return vec;
        }
        
        const map<int, string>& getM() const {
            return mp;
        }
        
    private:
        vector<string> vec;
        map<int, string> mp;
};

int main()
{
    string s;
    test t("hello ");
    s += t.getV().at(0);
    s += t.getV()[0];
    s += t.getM().at(0);
    s += t.getM()[0];
    cout << s;
}

std::map::operator[] 仅适用于非 const std::mapThe documentation on std::map::operator[] 很好地解释了这一点。这是页面开头的摘录:

Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.

如您所见,如果键不存在,它会在映射中插入一个新的 key/value 对。显然,这不适用于 const 映射,因为您不能向其中插入元素,因为它们是不可变的。为什么没有 const 不会创建新值的运算符重载,我不知道。但就是这样。

std::map::at(),但并不完全像 std::map::operator[]。同样,摘自 documentation of std::map::at():

Returns a reference to the mapped value of the element with key equivalent to key. If no such element exists, an exception of type std::out_of_range is thrown.

此外,该函数也有一个 const 重载:const T& at(const Key& key) const; 因此它可以用于 const 映射。


In addition, why both operator[] and .at() work for std::vector?

因为 std::vector::operator[] and std::vector::at() 的工作方式非常相似,除了 std::vector::at() 进行边界检查而 std::vector::operator[] 不进行边界检查。两者都不会创建新值(因为那不是向量的工作方式)并且都具有 const 重载。事实上,std::vector::operator[] 的文档甚至解决了它与 std::map::operator[]:

之间的区别

Unlike std::map::operator[], this operator never inserts a new element into the container. Accessing a nonexistent element through this operator is undefined behavior.

(这是未定义的行为,因为正如我之前提到的,operator[] 不进行边界检查。)

只是添加到,下面增加容器的大小:

class test {
    public:
           ...
           map<int, string>& getM() {
               return mp;
           }
    private:
           ...
}

int main()
{
    string s;
    test t("hello ");
    s += t.getV().at(0);
    s += t.getV()[0];
    s += t.getM().at(0);
    s += t.getM()[0];
    cout << s;
    cout << t.getM().size() << endl;  // prints 1
    auto temp = t.getM()[1]; // Key=1 does not exist in the container and hence is added
    cout << t.getM().size() << endl; // prints 2
}

另外,我从 clang 而不是 gcc 得到了关于这个问题的更好提示:

no viable overloaded operator[] for type 'const map<int, std::string>' (aka 'const map<int, basic_string<char> >')