Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying element of const std::vector<T> via const_cast

Does the following program have undefined behavior?

#include <iostream>
#include <vector>

struct Foo
{
    const std::vector<int> x;
};

int main()
{
    std::vector<int> v = {1,2,3};
    auto f = new Foo{v};
    const_cast<int&>(f->x[1]) = 42; // Legal?
    std::cout << f->x[1] << "\n";
}

Note that it not using const_cast to strip constness from f->x, but instead stripping constness from f->x[x], which presumably is represented by a separate array. Or is a translation allowed to presume that f->x[1] is immutable after it is created?

like image 397
Arch D. Robison Avatar asked May 03 '19 22:05

Arch D. Robison


People also ask

Can you change the elements of a const vector?

vector<const string>: Cannot change the values of the elements of this vector after they've been added. EDIT: This may fail to compile on a pre-C++11 compiler. const vector<string>: Cannot change anything about the vector.

Why const_ cast is used?

const_cast is one of the type casting operators. It is used to change the constant value of any object or we can say it is used to remove the constant nature of any object. const_cast can be used in programs that have any object with some constant value which need to be changed occasionally at some point.


Video Answer


1 Answers

There is no Undefined Behavior in your example.

The above code does not invoke undefined behavior because the underlying data (int) is mutable. Let's look at a simpler example.

#include <iostream>

struct IntPtr {
    int* data;
};

int main() {
    int a = 0;
    const IntPtr p { &a }; 
    *p.data = 10;
    std::cout << a; // Prints 10
}

All of this is perfectly legal to do because making IntPtr const results in data being a constant pointer to an int, NOT a pointer to a constant int. We can modify the data that p.data points to; we just can't modify p.data itself.

const IntPtr p { &a };

*p.data = 10; // This is legal

int b;
p.data = &b; // This is illegal (can't modify const member)

So how does this example apply to std::vector? Let's add the ability to index into an IntPtr:

class IntPtr {
    int* data;
   public:
    IntPtr() = default;
    IntPtr(int size) : data(new int[size]) {}
    
    // Even though this is a const function we can return a mutable reference 
    // because the stuff data points to is still mutable. 
    int& operator[](int index) const {
        return data[index]; 
    }
};

int main() {
    const IntPtr i(100); 
    i[1] = 10; // This is fine
};

Even though the IntPtr is const, the underlying data is mutable because it's created by allocating an array of mutable ints. It's the same for std::vector: the underlying data is still mutable, so it's safe to const_cast it.

like image 98
Alecto Irene Perez Avatar answered Nov 05 '22 04:11

Alecto Irene Perez