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.
Is this defined behavior or are the compilers not flagging UB?
CodePudding user response:
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
.
CodePudding user response:
Compilers are supposed to produce compile time errors on UB.
The above statement is incorrect unless explicitly specified by the standard.
Can contents of a
const vector
be modified w/o UB?
No. Trying to modify a const
variable leads to undefined behavior.
From dcl.type.cv:
Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.
(end quote)
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior. The program may just crash.
So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash.
So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.