1) Why are we allowed to change the value of the read-only const variable under any circumstances? Doesn't that defeat the purpose of using the const qualifier?
Attempting to modify an object with content via an assignment operator violates the restriction:
6.5.16 in Restrictions :
2 The assignment operator must have a mutable lvalue as its left operand.
The modifiable values ββof l are defined in 6.3.2.1 (1):
The modifiable value of lvalue is an lvalue that does not have an array type, does not have an incomplete type, does not have a const type , and if it is a structure or union, it has any member (including, recursively, any member or element of all contained aggregates or unions) with a categorical type.
As a violation of the restriction, a diagnostic message is required from the compiler in 5.1.1.3 (1):
The corresponding implementation should produce at least one diagnostic message (identified in a specific way) if the translation unit or translation unit contains a violation of any syntax rule or restriction, even if the behavior is also explicitly specified as undefined or determined by the implementation. Diagnostic messages should not occur under other circumstances.
But implementation is not required to reject invalid programs, so a diagnostic message can also be a warning instead of an error.
However, changing an object declared const through an lvalue that is not of type const is not a violation of the constraint, although it causes undefined behavior, 6.7.3 (6):
If an attempt is made to modify an object defined using a type specific to const using the value l with a non-constant type, the behavior is undefined.
Since this is not a violation of the constraint and invalid syntax, it does not even require a diagnostic message to be displayed.
Should we not get an error if we try to do this?
You should receive a diagnostic message if you try to modify an object using an lvalue of type const.
Since this is a blatant violation of stated intentions, most compilers emit an error in these circumstances.
If you try to change an object using a const-type using an lvalue with a non-constant qualification type, as in
const int i=8; int *ptr=&i; *ptr=9;
an attempt to change i to the expression *ptr = 9 causes undefined behavior, but is not a violation of the restriction (or a syntax error), therefore, it does not require a diagnostic message (and none are specified).
A diagnostic message is issued to initialize
int *ptr = &i;
as this again violates the restriction in accordance with 6.5.16.1 (1):
One of the following:
- the left operand is of atomic, qualified, or unskilled arithmetic type, and the right is of arithmetic type;
- the left operand has an atomic, qualified or unqualified version of the structure or type of association compatible with the type of law;
- the left operand has an atomic, qualified, or unqualified pointer type and (given the type that the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type indicated on the left are all type identifiers pointed to by the right ;
- the left operand has an atomic, qualified, or unqualified pointer type and (given the type that the left operand would have after lvalue conversion), one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to left, has all the qualifiers of the type that the right points to;
- the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
- the left operand is atomic, qualified, or unqualified _Bool, and the right is a pointer.
This diagnosis is usually a warning, not an error, since you can explicitly disable const ,
int *ptr = (int*)&i;
whereas it is impossible to discard const from i .
Modification of an object using a pointer to an object type not associated with a statement that was obtained by discarding const with a pointer to an object type with a const attribute is valid if the specified object is mutable. Silly example:
int i = 8; const int *cptr = &i; // valid, no problem adding const int *mptr = (int*)cptr; *mptr = 9; // no problem, pointee is non-const
2) Even if for some strange reason we are allowed to change constant values, why is there discrimination between changing the value of a constant variable, read-only, using a pointer (which is allowed with a warning) and using an assignment operation (which is simply not allowed and gives us a mistake)?
Direct assignment to an object with a const-qualified type is not only a violation of the restriction, but also an obvious violation of the specified semantics. The declaration of a const object explicitly says "I do not want this object to be modified."
Modifying an object with a pointer to a non-constant type is not a violation of the restriction, but only undefined behavior if the receiver has a const-qualified type. It is allowed to convert a pointer to a type defined using a constant, a pointer to the corresponding non-constant type, and changing the pointer through this pointer can be valid, so you only get a warning and only if the conversion is not explicit.
In the short example given, the compiler could detect that pointee is of type having const, and therefore the modification causes undefined behavior, but in general it would be difficult and often impossible to detect. Therefore, the compiler does not even try to detect simple cases; it is not worth the effort.