A const vector can't be modified as it's a const object. So inserts, appends, erases, are not allowed. However, its contents are not part of that object but are owned by it. As a similar example:
int* const p = new int[10]{1,2,3,4};
p
is a const object that owns non-const data which can be modified: p[1]=5;
Vector's operator[]
is conditioned on whether vector is const and if so returns a const int&
But if the underlying value wasn't const then a const cast removing const should be legal.
To test this I wrote the following program:
#include <vector>
constexpr int foo()
{
const std::vector<int> v{ 1,2,3 };
const int a[3]{ 1,2,3 };
*const_cast<int*>(&v[1]) = 21;
// However, this should fail and does on GCC and CLANG
//*const_cast<int*>(&a[1]) = 21;
return v[1];
}
int main()
{
constexpr int sb21 = foo();
const std::vector<int> v{ 1,2,3 };
*const_cast<int*>(&v[1]) = 21;
return v[1] + sb21;
}
MSVC, CLANG, and GCC all compile and execute.
The code evaluates a constexpr function at compile time. Compilers are supposed to produce compile time errors on UB. For comparison if the array, which contains const elements, is uncommented, Clang and GCC both produce errors as expected. However, MSVC does not which appears to be a bug.
Use case is having a fixed size vector that can't be structurally altered but can have contents updated.
std::vector<T>
uses std::allocator<T>
and so long as the library implementation of vector
doesn't use small sizes like std::string
's short string optimization then this should be defined behavior.
Here's an example showing how a const std::string
exhibits UB for small strings that are stored within the object while longer allocated ones do not:
#include <string>
consteval int foo()
{
const std::string v{ "1234" };
//const std::string v{ "123412341234123412341234" };
*const_cast<char*>(&v[1]) = 'A';
return v[1];
}
int main()
{
return foo();
}
Is this defined behavior or are the compilers not flagging UB?