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?

6
  • The cast in bar is a NOP anyway if I'm not too tired. Commented Nov 4, 2019 at 2:06
  • @Peter-ReinstateMonica I cast away constness to write to data. Commented Nov 4, 2019 at 2:09
  • See, I was tired and missed the const. I assume foo compiles? Interesting. Commented Nov 4, 2019 at 2:11
  • I used -std=c++17 -O3 -Wall -Werror with clang 9.0.0 and the whole thing compiles (even with bar instead of foo). Commented Nov 4, 2019 at 2:12
  • This is undefined behaviour due to strict aliasing rule violation (you alias const A * as A *) Commented Nov 4, 2019 at 3:59

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer. Now const_cast seems a bit redundant to me. Maybe there are use-cases I can't see.
@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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.