Why Isn't the [] Operator Const for Stl Maps

Why isn't the [] operator const for STL maps?

For std::map and std::unordered_map, operator[] will insert the index value into the container if it didn't previously exist. It's a little unintuitive, but that's the way it is.

Since it must be allowed to fail and insert a default value, the operator can't be used on a const instance of the container.

http://en.cppreference.com/w/cpp/container/map/operator_at

Why does const does not works with size() for stl map, whereas it works perfectly for other containers ?

You are not calling size() on the map. You are calling operator[] on the map, which is a non-const operation, since it will create an element at that position if one does not already exist.

You then attempt to call size() on the vector<string> at that position, but it is too late by this point. Incidentally, size() is const on Standard Library containers.

can't I use map [ ] operator with const function keyword?

The reason is because operator[] isn't const? I know that a const function can call only other const function.

Yes; operator[] is specified to create a new default-constructed element if the key doesn't exist, and this wouldn't be sensible on a const map, thus it's not marked as const.

Of course you could specify the const version to throw an exception (as at does) or - I don't know - call terminate if the key isn't found, but alas the standard doesn't say that. You'll either have to use at or (ugh) find.

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.

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.

Would really like to wrap my head around a 'const' issue with maps

If you look at the declaration for map's operator[], you will see that it is not const qualified, which is why it cannot be called on a const std::map<std::string, double>. The reason it is not const is because if the key does not exist in the map, it creates it. You should instead use find or at to get the element.

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

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.)

Idiomatic C++ for reading from a const map

template <typename K, typename V>
V get(std::map<K, V> const& map, K const& key)
{
std::map<K, V>::const_iterator iter(map.find(key));
return iter != map.end() ? iter->second : V();
}

Improved implementation based on comments:

template <typename T>
typename T::mapped_type get(T const& map, typename T::key_type const& key)
{
typename T::const_iterator iter(map.find(key));
return iter != map.end() ? iter->second : typename T::mapped_type();
}

c++ Map [] operator not found

You're using the overridden operator[], which must have non-const access to the underlying map, as it will add a new entry if one doesn't exist at the requested key location. In your case that will add a NULL pointer (not going into the reasons for why).Your member function is declared as const, and therefore the map is not modifiable.

Either declare the map as mutable (NOT recommended), or use an iterator-search and return NULL if the search returned keywordItems.end(). Otherwise, return the iterator's object (in it->second).

Example

const ItemSet* Library::itemsForKeyword(const string& keyword) const
{
std::map<std::string, ItemSet*>::const_iterator it = keywordItems.find(keyword);
if (it != keywordItems.cend())
return it->second;
return nullptr;
}

Note: I would strongly advise using either direct objects, or at least smart pointers (such as std::shared_ptr<ItemSet>) for your map object content. RAII: Its whats for dinner.



Related Topics



Leave a reply



Submit