I would like to create a const std::vector<T>
that can store updateable values that user code can access but not (easily) modify. There are several advantages to this. The vector object (but not its contents) cannot be changed. So references to entries in the vector can be established without risk of dangling if someone decides later to add new elements or other operations that can cause dangling references. And, since it would be a complete const object, it cannot be modified even using placement-new
without UB and/or compiler complaints.
This seems to be possible because, while the vector object is const, the T
s are not and must be stored as non-consts. Attempting to store them as const produces the following error:
The C++ Standard forbids containers of const elements because
allocator<const T>
is ill-formed.
See this
So, since the T
's are not const, but are only made to appear const when accessed, it appears that they may be accessed and updated by using a const_cast
to remove the const.
I haven't run across this use of modifiable const vectors, but it appears to be quite legal. Am I missing something?
Here's the code including constexpr
for additional UB testing:
#include <vector>
#include <iostream>
constexpr int foo()
{
const std::vector<int> v{ 1,2,3 };
const int& rci = v[0]; // A const ref to v[0] is ok
int& ri = const_cast<int&>(v[0]); // A ref to v[0] as a non-const requires a cast
ri = 42; // v[0] is now 42;
return v[0];
}
void update_const_v(const std::vector<int>& v)
{
for (const int& i : v)
const_cast<int&>(i) = i + 1;
}
void print(const std::vector<int>& v)
{
for (auto& i:v)
std::cout << i << '\n';
std::cout << '\n';
}
int main()
{
const std::vector<int> v{ 1,2,3 };
const int& ri = v[0]; // A ref to v[0]
print(v);
update_const_v(v);
print(v);
std::cout << "Reference to first element of const vector: " << ri << '\n';
// Check for UB using constexpr
constexpr int i = foo();
return i;
}
And here's it running in msvc, clang, and gcc.