0

I have some code that looks like this:

void addPtrs(vector<Thing*> & ThingPtrs, const vector<Thing> & actualThings) {
       for (const Thing & t : actualThings)
           if (/*some condition*/)
               ThingPtrs.push_back(&t);
}

Basically, I want to modify ThingPtrs by giving it pointers to Things that have some condition. However, because I do not want to modify the actual Thing, I labeled actualThings as const, and now I can't assign a const pointer to a nonconst pointer.

Obviously one solution is to simply not make actualThings const, but I don't actually intend to modify it. Another solution is using a const_cast, but I would like to avoid that if possible too.

What are my options in a situation like this?

Dillydill123
  • 693
  • 7
  • 22
  • If you never intend to modify any `Thing`, your `ThingPtrs` would be defined as `std::vector&`. Seeing that it stores non-`const` pointers, it implies that some modification _will_ be required at some point, so you don't want any `const`ness. – Algirdas Preidžius Jan 12 '17 at 02:34
  • I intend to modify `Thing`s, but only through `actualThings` isntead of `ThingPtrs`. Could I define `ThingPtrs` to be of type `vector`? – Dillydill123 Jan 12 '17 at 03:28
  • @Dillydill123 Yes, if you change `ThingPtrs` to be `vector` then your function should compile fine. – François Andrieux Jan 12 '17 at 03:38

1 Answers1

2

By design, const std::vector will not allow you to modify it's elements directly. Since actualThings is const you cannot modify it's content. Any reference or pointer to it's elements will be const.

Any solution you find without changing the function's prototype will ultimately involve converting a const Thing & or const Thing * to it's non-const equivalent, regardless of how you dress it. Any pointer cast or reinterpretation would just be a round-about const_cast.

If you are concerned that addPtrs does not modify actualThings (in the sense of calling it's non-const member) you could change your interface to accept a begin/end pair of iterators. Other changes that will allow your function to compile include removing const from actualThings to get vector<Thing> & actualThings or adding const to the type of elements in ThingPtrs to get vector<const Thing*> & ThingPtrs

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • So I tried `vector` and I'm surprised this compiled. How is this allowed, given that when a `vector` reaches capacity, it has to remake the its container? I also noticed that `vector` doesn't compile. – Dillydill123 Jan 12 '17 at 03:53
  • 1
    @Dillydill123 This approach does not protect against invalidation. It will indeed break if/when `actualThings` resizes. All pointers and references to elements, along with all iterators are invalidated when that happens. A const pointer **does not guarantee that the pointed object can't change**, only that you can't change it using the pointer. For your other question, see [this question](http://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const) for more information on the different places you can put const on a pointer type. – François Andrieux Jan 12 '17 at 04:06
  • @Dillydill123 for your 2nd question in comment, just to make sure, you know the difference between `const X*`/ `X const *` vs `X * const` right? (pointer to const X vs const pointer to X) – Adrian Shum Jan 12 '17 at 04:09
  • Yup I do! I believe I understand why we can't have `vector` Correct me if I am wrong, but it doesn't compile because a const pointer would need to be initialized when it is created, which won't be the case if it lives inside the vector. Now this gives me yet another question! Could we do map? It seems like that should work! – Dillydill123 Jan 12 '17 at 04:20
  • @Dillydill123 `int * const` is a pointer to a mutable (non-const) `int` and it can't be assigned to a new address once initialized. It still has the same problem as `vector` where you can't assign a `const int *` to it. It also has a new issue because [std::vector](http://en.cppreference.com/w/cpp/container/vector) requires that `T` be [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable). – François Andrieux Jan 12 '17 at 04:28
  • Thanks so much guys, this was incredibly helpful – Dillydill123 Jan 12 '17 at 04:33