1

I am trying to understand some details of static_cast.

Please have a look at the following code,

struct A
{
    int data = 0;
};

void foo(const A* a)
{
    (*static_cast<A**>(static_cast<void*>(&a)))->data = 1;
}

void bar(const A* a)
{
    const_cast<A*>(a)->data = 1;
}

int main()
{
    A a;
    foo(&a);
    return a.data;
}

Is the function foo valid C++ code? Is there any valid usage that gives a different result with foo vs. bar?

Empty Space
  • 743
  • 6
  • 17

1 Answers1

3

Both functions are valid C++ and have well-defined behavior (modifying the data member of the A object created in main) in C++11 and later.

You are allowed to obtain a pointer to non-const from a pointer to const object type either directly with const_cast or indirectly with static_cast going through void* as you are doing in foo. That in itself is not a problem:

The cast to void* is possible because &a is a pointer to const A* which is not (top-level) cv-qualified. The cast from void* to A** is possible because void* can be cast to any object pointer type. Dereferencing the result is accessing the const A* object through a pointer to A*, but that is ok because the types are similar. (The last part seems to have been an aliasing rule violation prior to C++11, making this undefined behavior.)

However, modifying a const qualified object through a pointer to non-const obtained in such a way causes undefined behavior.

Since the object A a; that you are passing to the function is not const qualified, there is no problem.

But I think it is obvious why using such functions is dangerous. Changing the declaration A a; to const A a; will still compile because there is no type mismatch, but will have undefined behavior.

Both functions do exactly the same thing in all situations, as far as I can tell.

walnut
  • 21,629
  • 4
  • 23
  • 59
  • Thanks for the answer. Now `const_cast` seems a bit redundant to me. Maybe there are use-cases I can't see. – Empty Space Nov 04 '19 at 04:51
  • 1
    @MutableSideEffect The intent of `const_cast` is to explicitly state what is happening, because as I mentioned in my answer, using it is always dangerous and requires special care to be taken. If you are talking strictly about redundance, then `((A*)a)->data = 1;` would also do it and C style cast allows most other casts as well. – walnut Nov 04 '19 at 05:57