Reputation: 967
How much const
should you apply to a std::map
?
// Given a custom structure, really any type though
struct Foo
{
int data;
};
// What's the difference between these declarations?
const std::map<int, Foo> constMap;
const std::map<const int, const Foo> moreConstMap;
What are the tradeoffs or differences between constMap
and moreConstMap
?
The answer may apply to other stl containers too.
Edit1.
To provide some more context. One potential use case to consider the difference between the two might be a static lookup table scoped to a .cpp file. Let's say...
//Foo.cpp
namespace {
const std::map<int, Foo> constConfigMap{ {1, Foo{1}}, {2, Foo{2}} };
// vs
const std::map<const int, const Foo> moreConstConfigMap{ {1, Foo{1}}, {2, Foo{2}} };
}
void someFunctionDefinition()
{
Foo blah { constConfigMap.at(2) };
// do something with blah
}
Upvotes: 2
Views: 1678
Reputation: 94
std::map
contains pair
's of {key, value}
. key
is always constant and you can not modify it. On the other hand, value
is modifiable, and if you use const
, it's not. Because of those const
at the beginning, anything is modifiable, so the answer to you question is that they are exactly the same. There is no differences.
Upvotes: 1
Reputation: 14589
There is no difference in case of std::map
aside of them being distinct types.
As variables are declared const
, the state of map class itself cannot be changed.
Only member functions you can call upon it are const-qualified member functions, e.g. const_iterator find( const Key& key ) const;
Both const-qualified find()
will return a const_iterator
which would be referring an object of const std::pair<const int, Foo>
type (just as operator[]
would) in case of constConfigMap
and const std::pair<const int, const Foo>
in case of moreConstConfigMap
. Those types are nearly synonyms because second
member of std::pair
isn't declared as mutable
. Those are different types though because they are declared by different set of lexemes, which can be illustrated by following code:
struct Foo
{
int data;
void bar() {}
// needs to be const-qualified
bool operator==(const Foo& other) const { return data == other.data; }
};
namespace {
const std::map<int, Foo> constConfigMap{ {1, Foo{1}}, {2, Foo{2}} };
// vs
const std::map<const int, const Foo> moreConstConfigMap{ {1, Foo{1}}, {2, Foo{2}} };
}
int main() {
auto it1 = constConfigMap.find(1);
auto it2 = moreConstConfigMap.find(1);
*it1 == *it2; // error: no match for ‘operator==’
it1->second == it2->second;
it1->second.bar(); // error: passing ‘const Foo’ as ‘this’ argument discards qualifiers
// neither is ill-formed, what would happen is other question
const_cast<Foo&>(it1->second).bar();
const_cast<Foo&>(it2->second).bar();
return 0;
}
Compiler would point out that those are different types.
| *it1 == *it2;
| ~~~~ ^~ ~~~~
| | |
| | pair<[...],const Foo>
| pair<[...],Foo>
You can't change either map or its elements at all. You can't call non-const-qualified members upon an instance of Foo
without discarding const
.
Upvotes: 2
Reputation: 41474
As has already been mentioned, keys in a map are implicitly const.
Making the value a const type will prevent you from using mymap[k] = v
, because the index operator will return a reference to const. You’ll need to use insert/emplace
and erase
to modify the map.
Upvotes: 1