-4

I want to cast a std::vector<int> to const std::vector<const int>, it seems that it can not be automatically casted. So I have some questions:

  1. I can easily cast std::vector<int> to const std::vector<int>, why is that?

  2. If I want to cast to const std::vecor<cosnt int>, how should I do that? I've tried const_cast but doesn't work

Ziqi Liu
  • 2,931
  • 5
  • 31
  • 64
  • 5
    `std::vector` won't compile, you can't have const elements. – Galik Jul 31 '18 at 20:24
  • 1
    You can't have a vector containing a `const` type. You can't have any STL container with `const` element type. See https://stackoverflow.com/questions/8685257/why-cant-you-put-a-const-object-into-a-stl-container – Silvio Mayolo Jul 31 '18 at 20:24
  • I wonder what kind of "easy" cast would allow what you report in your first bullet. – Quentin Jul 31 '18 at 20:26
  • What is the purpose of this? If you want to make sure the data in the vector is not mutated then you can use its `const_iterator`'s. – NathanOliver Jul 31 '18 at 20:29

1 Answers1

6

If I want to cast to const std::vecor<cosnt int>, how should I do that? I've tried const_cast but doesn't work

Short answer: Don't.

When you make a std::vector<int> const, as-in const std::vector<int>, the contents themselves become implicitly const as well. In other words, if you write something like this, you won't be able to modify the elements:

const std::vector<int> values{1,2,3,4,5};

//Nope
//values.emplace_back(6);

//Also Nope
//values[3] = 5;

//Still nope
//values.erase(values.begin() + 1, values.begin() + 3);

//Nuh-uh
//std::vector<int> & mutable_values = values;

//This, however, is okay.
std::vector<int> const& immutable_values = values;

//Same restrictions though
//immutable_values[2] = 6;
//immutable_values.emplace_back(7);

//This is fine
std::vector<int> copy_of_values = values;

//But that's because you made a copy
copy_of_values.emplace_back(6);
assert(copy_of_values.size() != values.size());
assert(copy_of_values != values);

This is why STL containers like std::vector, std::list, std::map, and so on, prohibit the use of const members within their template parameter lists: because making the container itself const also makes its contents const, which is a stated contract of the design of these containers. Some "containers" don't have this property, like Smart Pointers, which is why you'll sometimes see stuff like this:

std::shared_ptr<int> ptr = std::make_shared<int>(42);
std::shared_ptr<const int> non_modifying_ptr = ptr;

Which is part of the core functionality of reference-counted pointers.

This, incidentally, is all part of making sure your code is "const-correct", and I strongly advise you do a google search on that very subject and learn about what it is, and how to properly apply it in your code to make your code safer and more performant.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Xirema
  • 19,889
  • 4
  • 32
  • 68
  • I'd add that if you declared `const std::vector` and you wanted to perform a simple `push_back()` you'd have to `const_cast`. But declaring an object as const and then const_casting it many times is pretty useless... – Alberto Miola Jul 31 '18 at 20:33
  • 2
    @AlbertoMiola That would be undefined behavior, actually. It's perfectly legal to `const_cast` away the `const`-ness of an object if you ***know*** that the object wasn't originally declared `const`, but if the object *was* declared `const`, then it's UB, and unsafe. – Xirema Jul 31 '18 at 20:35
  • I was referring to the parameter passing way of declaring an array const, since the OP seemed to be confused about it. I should have specified I was referring to that! – Alberto Miola Jul 31 '18 at 20:37