5
votes

I have been overthinking (some may say underthinking, let's see what happens) the const-ness of STL containers and their elements.

I have been looking for a discussion of this, but the results have been surprisingly sparse. So I'm not necessarily looking for a definite answer here, I'd be just as happy with a discussion that gets the gears in my head moving again.

Let's say I have a class that keeps std::strings in a std::vector. My class is a dictionary that reads words from a dictionary file. They will never be changed. So it seems prudent to declare it as

std::vector<const std::string> m_myStrings;

However, I've read scattered comments that you shouldn't use const elements in a std::vector, since the elements need to be assignable.

Question:

  • Are there cases when const elements are used in std::vector (excluding hacks etc)?

  • Are const elements used in other containers? If so, which ones, and when?

I'm primarily talking about value types as elements here, not pointers.

4

4 Answers

4
votes

My class is a dictionary that reads words from a dictionary file. They will never be changed.

Encapsulation can help here.

Have your class keep a vector<string>, but make it private. Then add an accessor to your class that returns a const vector<string> &, and make the callers go through that.

The callers cannot change the vector, and operator [] on the vector will hand them const string &, which is exactly what you want.

2
votes
2
votes

In the context of std::vector, I don't think it makes sense to use a const qualifier with its template parameter because a std::vector is dynamic by nature and may be required to "move" in memory in order to "resize" itself.

In the C++03 standard, std::vector is guaranteed stored in contiguous memory. This almost requires that std::vector be implemented with some form of an array. But how can we create a dynamic size-changing array? We cannot simply just "append" memory to the end of it--that would either require an additional node (and a linked list) or actually physically putting our additional entries at the end of the array, which would be either out-of-bounds or require us to just reserve more memory in the first place.

Thus, I would assume that std::vector would need to allocate an additional array, copy or move its members over to the end array, and then delete the old one.

It is not guaranteed that a move or copy assignment for every template-able object for a std::vector would not change the underlying object being moved or copied--it is considered good form to do add the const qualifier, but it is not required. Therefore, we cannot allow a std::vector<const T>.

Related: How is C++ std::vector implemented?

-1
votes

consider using

std::vector<std::shared_ptr<const std::string>> 

instead?