Why does std::map not have a const accessor?
operator[]
in a map returns the value at the specified key or creates a new value-initialized element for that key if it's not already present, so it would be impossible.
If operator[]
would have a const
overload, adding the element wouldn't work.
That answers the question. Alternatives:
For C++03 - you can use iterators (these are const
and non-const
coupled with find
). In C++11 you can use the at
method.
Is the at() const accessor for map standard in C++11?
Yes. std::map
has an at
member function in C++11 with the following specification (23.4.4.3/9):
T& at(const key_type& x);
const T& at(const key_type& x) const;Returns: A reference to the mapped_type corresponding to
x
in*this
.Throws: An exception object of type
out_of_range
if no such element is present.Complexity: logarithmic.
Note however that this member function has been added specifically to std::map
. It is not required by the more general associative container requirement. If you are writing generic code that requires some associative container type, you can't use this new at
. Instead, you should continue to use find
, which is part of the associative container concept, or write your own non-member helper:
template <typename AssociativeContainer>
typename AssociativeContainer::mapped_type&
get_mapped_value(AssociativeContainer& container,
typename AssociativeContainer::key_type const& key)
{
typename AssociativeContainer::iterator it(container.find(key));
return it != container.end() ? it->second : throw std::out_of_range("key");
}
template <typename AssociativeContainer>
typename AssociativeContainer::mapped_type const&
get_mapped_value(AssociativeContainer const& container,
typename AssociativeContainer::key_type const& key)
{
typename AssociativeContainer::const_iterator it(container.find(key));
return it != container.end() ? it->second : throw std::out_of_range("key");
}
Or, if you have an implementation that supports rvalue references and decltype
, you don't need two overloads:
template <typename AssociativeContainer, typename Key>
auto get_mapped_value(AssociativeContainer&& container, Key const& key)
-> decltype(std::declval<AssociativeContainer>().begin()->second)&
{
auto const it(container.find(key));
return it != container.end() ? it->second : throw std::out_of_range("key");
}
(Or something close to that; one fun thing about C++11 is that no two compilers have the same bugs and all seem to accept slightly different subsets of valid--and invalid--C++11 code.)
Why does the following not work when the map is const static
Using operator[]
on a std::map
creates the object if it doesn't exist. So it's an operation that can only be performed on a map you are allowed to modify. Use find instead.
C++ map access discards qualifiers (const)
std::map
's operator []
is not declared as const
, and cannot be due to its behavior:
T& operator[] (const Key& key)
Returns a reference to the value that is mapped to a key equivalent to key, performing insertion if such key does not already exist.
As a result, your function cannot be declared const
, and use the map's operator[]
.
std::map
's find()
function allows you to look up a key without modifying the map.
find()
returns an iterator
, or const_iterator
to an std::pair
containing both the key (.first
) and the value (.second
).
In C++11, you could also use at()
for std::map
. If element doesn't exist the function throws a std::out_of_range
exception, in contrast to operator []
.
Compiler error when attempting to access std::map element with operator[]
It seems that m_components
is of type ComponentMap*
.
When you write m_components["Armor"]
compiler interprets that as an access to "Armor"
-th element of dynamic array of ComponentMap
s, which does not make any sense.
What you want is (*m_components)["some string"]
. This will invoke operator[]
of ComponentMap
, but as Luchian Grigore and Olaf Dietsche mention, std::map::operator[]
does not have a const overload, so this will fail too. The only option left is to use find
.
The simplified edition will be:
Armor* Character::getArmor() const
{
return static_cast<Armor*>(m_components->find("Armor")->second);
}
Weapon* Character::getWeapon() const
{
return static_cast<Weapon*>(m_components->find("Weapon")->second);
}
Attributes* Character::getAttributes() const
{
return static_cast<Attributes*>(m_components->find("Attributes")->second);
}
This code does not have the same behaviour as your original example and will fail if m_components
does not have "Armor"
, "Weapon"
and "Attributes"
elements.
The closest we can get is to explicitly handle absence of element and return 0
or nullptr
if you use C++11.
Final correct C++03 compatible edition:
Armor* Character::getArmor() const
{
ComponentMapCIter i = m_components->find("Armor");
if (i != m_components->end())
return static_cast<Armor*>(i->second);
return 0;
}
Weapon* Character::getWeapon() const
{
ComponentMapCIter i = m_components->find("Weapon");
if (i != m_components->end())
return static_cast<Weapon*>(i->second);
return 0;
}
Attributes* Character::getAttributes() const
{
ComponentMapCIter i = m_components->find("Attributes");
if (i != m_components->end())
return static_cast<Attributes*>(i->second);
return 0;
}
Why is a default constructor required when storing in a map?
mymap["hello"]
can attempt to create a value-initialized A
, so a default constructor is required.
If you're using a type T
as a map
value (and plan to access value via operator[]
), it needs to be default-constructible - i.e. you need a parameter-less (default) constructor. operator[]
on a map will value-initialize the mapped value if a value with the key provided is not found.
C++ error: passing 'const std::mapint, std::basic_stringchar ' as 'this' argument of ...
string color::getColorText() const {
return colors[cColortype];
}
The issue is that you've marked the function as const
. The operator[]
on std::map
is marked as non-const, and cannot be used in a const function like this. You need to manually use std::map::find
(or other mechanism) to search for the input type and handle the case where it's not found.
If you're using C++11, you can instead use std::map::at
, which IS allowed to be used on a constant map, and throws an exception if the requested element is not present.
Does std::map require the comparator's operator() to be const?
Well, yes: The comparator is a subobject of the map itself, one way or another (maybe a member; usually a base class of some inner implementation class). If you have a constant reference to the map, the comparator still needs to be usable for lookup, so the operator needs to be const
.
Why can't I have two accessors for the same element in tbb hash map?
An accessor allows write access. This means a write lock is acquired, and held by no more than a single accessor. You enter a deadlock because the same thread attempts to lock the same element for writing via different accessors.
If all you want is to read the data, then use a const_accessor
with find
. It will acquire a read lock only. Multiple read locks can be acquired and held without deadlocking.
concurrent_hash_map<int, int>::const_accessor a1, a2;
Related Topics
What Are the Different Character Sets Used For
What Does the C++ New Operator Do Other Than Allocation and a Ctor Call
Factor a Large Number Efficiently with Gmp
Convert Byte Array into Bitset
Optimizing a Branch for a Known More-Common Path
How to Share Memory Between Linux Program and Windows Program Running Through Wine (Same Computer)
How to Construct or Return the Underlying Deque from a Stack
How to Call C or C++ Functions from Rust Code
Correct Way to Check If Windows Is 64 Bit or Not, on Runtime? (C++)
Determine How Many Times File Is Mapped into Memory
Using Boost Tokenizer Escaped_List_Separator with Different Parameters
What Expressions Create Xvalues
Convert from Utf-8 to Unicode C++
C++ Over Qt:Controlling Transparency of Labels and Buttons
How to Call a Constructor on an Already Allocated Memory