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
}
CodePudding user response:
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.
CodePudding user response:
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 beggining, anything is modifiable, so the answer to you question is that they are exactly the same. There is no diferences.
CodePudding user response:
How much
const
should you apply to astd::map
?
Very seldomly: Any. You would usually keep your map
confined in a class
and only expose it via member functions.
What are the tradeoffs or differences between constMap and moreConstMap?
It depends on what constMap
and moreConstMap
really means. They are not standardized. Standard const
s may make it possible for the optimizing part of the compiler to make assumptions to exclude certain branches in code that would actually be able to change the variable. Not needing to deal with those branches may make a program a bit faster.
CodePudding user response:
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
.