Why is it allowed in C++ to modify a constant object's pointer member variable's memory from outside?

3.4k Views Asked by At

I've been trying to understand when I write a function in C++ with a constant argument and a pointer variable inside of that object than the const flag is not protecting the underlying memory against modifications. For example it's perfectly legal to do the following in the operator=() function of the class called X:

class X
{
public:
    X& operator=(const X& other)
    {
        this->data = other.data; //(*)
        return *this;
    }

private:
    int* data;
};

(*): This is the same as the following:

int* some_pointer;
int* const other_pointer = some_pointer;
int* class_pointer = other_pointer;

But not the same as:

const int* other_pointer; 
int* class_pointer = other_pointer;

Which would generate the following error:

error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
 int* class_pointer = other_pointer;
                      ^

I understand why other.x is being casted to a int* const but I don't see why it isn't being casted to a const* int at the same time (which is a const int* const). When I write a function with a const argument my logic suggests anything inside that argument should inherit the constness because that should be the purpose of const, to protect the underlying data against modification.

When a pointer member is being accessed from outside of the const version of a class I think it should be a reasonable expectation that the object's const keyword should protect anything (even the memory) that gets out of the class from modification. The argument against this is that the outside memory does not belong to the object so it shouldn't be it's responsiblity to protect it either. My perspective on it is that in this case (out of any other cases when it's being accessed somewhere else with any kind of access rights) we are taking something out of a const object. In other words it's giving visibility to something outside of itself. So what's the reason behind not making the visibility const? That wouldn't change the accessibility rights of the memory in any other location of the code!

4

There are 4 best solutions below

4
On

"When I write a function with a const argument my logic suggests anything inside that argument should inherit the constness because that should be the purpose of const, to protect the underlying data against modification."

You are quite right about this, however the pointer stored inside the X-object points outside the object. The outside isn't affected by X's constness, just the data stored inside X.

0
On

You're not changing the value of other.data, so there's no const violation. You could certainly modify the object that other.data points to, but that's beyond the compiler's responsibility to enforce const-correctness.

1
On
int* const other_pointer
declare other_pointer as const pointer to int

as opposed to:

const int* other_pointer
declare other_pointer as pointer to const int

courtesy of http://cdecl.org/

Note the difference in the placement of const.

0
On

Why do you think that, because the pointer is constant, that which is pointed to should be constant? It does not necessarily follow.

Sometimes you need a pointer that must always point to a particular place, but through which you can modify the indicated place. There's nothing about class X which suggests that you shouldn't be able to change the memory data points to.

More importantly, you're thinking wrongly about the const keyword. Given

X& operator=(const X& other)

all you are doing is telling the compiler that you do not intend to change other inside operator=() and asking the compiler to prevent you from doing so in case you forget. Nothing more, nothing less. It says nothing at all about the const-ness of other outside of operator=() nor of the const-ness of anything any pointer inside other points to.