6

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.

Brian
  • 14,610
  • 7
  • 35
  • 43
Leander
  • 121
  • 3

4 Answers4

4

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.

Marshall Clow
  • 15,972
  • 2
  • 29
  • 45
  • That's a good suggestion and it's pretty much what I decided to do. Since your solution requires making a copy of the whole vector, though, I'll probably provide an interface similar to this: `void iterateWords(std::function func);`: then callers can supply a lambda function to do whatever they want with the strings. – Leander May 14 '15 at 15:53
2

No, for the reason you state.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
2

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?

Community
  • 1
  • 1
CinchBlue
  • 6,046
  • 1
  • 27
  • 58
-1

consider using

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

instead?