Reputation: 37
My problem is why the s += t.getM()[0]; in the example code raise
main.cpp:44:20: error: passing ‘const std::map >’ as ‘this’ argument discards qualifiers [-fpermissive]
I checked the cppreference and it says both return a reference.
In addition, why both operator[] and .at() work for std::vector?
Example code is here.
#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;
}
Upvotes: 0
Views: 1335
Reputation: 462
Just to add to @mediocrevegetable1's answer above, the following increases the size of the container:
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
}
Also, I got better hint regarding the issue from clang instead of gcc:
no viable overloaded operator[] for type 'const map<int, std::string>' (aka 'const map<int, basic_string<char> >')
Upvotes: 0
Reputation: 4217
std::map::operator[]
only works for a non-const
std::map
. The documentation on std::map::operator[]
explains this pretty well. Here's an excerpt from the beginning of the page:
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.
As you can see, if the key doesn't exist, it inserts a new key/value pair into the map. Obviously, this wouldn't work for const
maps because you can't insert elements into them since they're immutable. Why there isn't a const
overload for the operator that will not create a new value, I don't know. But that's just how it is.
std::map::at()
, however doesn't work exactly like std::map::operator[]
. Again, an excerpt from the 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.
Furthermore, the function has a const
overload too: const T& at(const Key& key) const;
So it can work for const
maps.
In addition, why both operator[] and .at() work for std::vector?
Because std::vector::operator[]
and std::vector::at()
work very similarly, except std::vector::at()
does bounds checking while std::vector::operator[]
doesn't. Neither will create a new value (because that's just not how vectors work) and both have const
overloads. In fact, the documentation for std::vector::operator[]
even addresses the difference between it and 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.
(It's undefined behavior because, as I previously mentioned, operator[]
does no bounds checking.)
Upvotes: 1