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;
}
compiler explorer
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();
}
Compiler Explorer
Is this defined behavior or are the compilers not flagging UB?
But if the underlying value wasn't const then a const cast removing const should be legal.
This is the weak point of your argument. It's not the underlying value that matters, but the owned object. If the owned object is not a const
object, then removing the cast should be legal. However, can you prove that the owned object is not const
?
I believe you cannot. Take your own example – a vector containing three int
s. Hypothetically, suppose each int
is 4 bytes, so the total data is 12 bytes. Also suppose the size of a vector is 24 bytes (allowing 8 bytes for each of a pointer, size, and capacity). It would not be unreasonable to optimize a bit and store the three int
s in the vector itself, along with a flag to say that the data is inside the vector instead of being dynamically allocated (a similar approach is used in short string optimization).
Now that we have the possibility that the data is inside the vector itself, we have the possibility that the data is part of a const
object, because the vector is const
. Casting away this const
ness to change a value is undefined behavior.
The bottom line is that if you do not own the object, you cannot know for sure how it was created. If the owner tells you it is const
, then you have to treat it as const
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With