Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is writing to a non-const object after casting away const of pointer to that object not UB?

According to the C++ Standard it's okay to cast away const from the pointer and write to the object if the object is not originally const itself. So that this:

 const Type* object = new Type();
 const_cast<Type*>( object )->Modify();

is okay, but this:

 const Type object;
 const_cast<Type*>( &object )->Modify();

is UB.

The reasoning is that when the object itself is const the compiler is allowed to optimize accesses to it, for example, not perform repeated reads because repeated reads make no sense on an object that doesn't change.

The question is how would the compiler know which objects are actually const? For example, I have a function:

void function( const Type* object )
{
    const_cast<Type*>( object )->Modify();
}

and it is compiled into a static lib and the compiler has no idea for which objects it will be called.

Now the calling code can do this:

Type* object = new Type();
function( object );

and it will be fine, or it can do this:

const Type object;
function( &object );

and it will be undefined behavior.

How is compiler supposed to adhere to such requirements? How is it supposed to make the former work without making the latter work?

like image 676
sharptooth Avatar asked Dec 16 '11 06:12

sharptooth


People also ask

Can a const reference be bound to a non-const object?

No. A reference is simply an alias for an existing object. const is enforced by the compiler; it simply checks that you don't attempt to modify the object through the reference r .

Is a non-const pointer that points to a constant value?

A pointer to a const value (sometimes called a pointer to const for short) is a (non-const) pointer that points to a constant value. In the above example, ptr points to a const int . Because the data type being pointed to is const, the value being pointed to can't be changed. We can also make a pointer itself constant.

Can a const function return a non-const pointer?

Do not return non-const handles to Class data from const member Functions. From a language point of view, the pointer 'p' is part of the class and then cannot be modified in a 'const' function. But the pointed-to value is not part of the class, and may be modified.

Can const methods be used by non-const objects?

When a function is declared as const, it can be called on any type of object, const object as well as non-const objects. Whenever an object is declared as const, it needs to be initialized at the time of declaration. however, the object initialization while declaring is possible only with the help of constructors.


2 Answers

When you say "How it is supposed to make the former work without making the latter work?" an implementation is only required to make the former work, it needn't - unless it wants to help the programmer - make any extra effort in trying to make the latter not work in some particular way. The undefined behavior gives a freedom to the implementation, not an obligation.

Take a more concrete example. In this example, in f() the compiler may set up the return value to be 10 before it calls EvilMutate because cobj.member is const once cobj's constructor is complete and may not subsequently be written to. It cannot make the same assumption in g() even if only a const function is called. If EvilMutate attempts to mutate member when called on cobj in f() undefined behavior occurs and the implementation need not make any subsequent actions have any particular effect.

The compiler's ability to assume that a genuinely const object won't change is protected by the fact that doing so would cause undefined behavior; the fact that it does, doesn't impose additional requirements on the compiler, only on the programmer.

struct Type {
    int member;
    void Mutate();
    void EvilMutate() const;
    Type() : member(10) {}
};


int f()
{
    const Type cobj;
    cobj.EvilMutate();
    return cobj.member; 
}

int g()
{
     Type obj;
     obj.EvilMutate();
     return obj.member; 
}
like image 143
CB Bailey Avatar answered Sep 19 '22 05:09

CB Bailey


The compiler can perform optimization only on const objects, not on references/pointers to const objects (see this question). In your example, there is no way the compiler can optimize function, but he can optimize the code using a const Type. Since this object is assumed by the compiler to be constant, modifying it (by calling function) can do anything, including crashing your program (for example if the object is stored in read-only memory) or working like the non-const version (if the modification does not interfere with the optimizations)

The non-const version has no problem and is perfectly defined, you just modify a non-const object so everything is fine.

like image 31
Luc Touraille Avatar answered Sep 21 '22 05:09

Luc Touraille