Is const_cast safe?
Asked Answered
P

6

97

I can't find much information on const_cast. The only info I could find (on Stack Overflow) is:

The const_cast<>() is used to add/remove const(ness) (or volatile-ness) of a variable.

This makes me nervous. Could using a const_cast cause unexpected behavior? If so, what?

Alternatively, when is it okay to use const_cast?

Phillane answered 10/12, 2008 at 21:1 Comment(3)
The top answer overlooks something that might be horribly obvious but is worth stating: It only becomes unsafe if you attempt to modify an originally const object via a de-const-ed reference/pointer. If, instead, you're merely const_casting to work around a poorly (or, in my case, lazily) spec'd API that only acceptd a non-const reference but will only be used in const methods... no problem whatsoever.Siding
@underscore_d: A more precise version of the question (and answer) that covers that is: Is it allowed to cast away const on a const-defined object as long as it is not actually modified?Unlock
Does this answer your question? Is it allowed to cast away const on a const-defined object as long as it is not actually modified?Recently
U
94

const_cast is safe only if you're casting a variable that was originally non-const. For example, if you have a function that takes a parameter of a const char *, and you pass in a modifiable char *, it's safe to const_cast that parameter back to a char * and modify it. However, if the original variable was in fact const, then using const_cast will result in undefined behavior.

void func(const char *param, size_t sz, bool modify)
{
    if(modify)
        strncpy(const_cast<char *>(param), sz, "new string");
    printf("param: %s\n", param);
}

...

char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true);  // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true);  // UNDEFINED BEHAVIOR
Ullage answered 10/12, 2008 at 21:4 Comment(13)
It's not true. C++ standard. §7.1.​5.1/4 says Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior Any attempt! There are no words about original variable.Hitherto
@Alexey: The original variable is about what is pointed to or referred to. You can take a const reference to a non-const object, and therefore, casting it to a writable reference is well-defined behaviour as the referred-to object is not actually const.Killing
@DeadMG: You can take a const reference to a non-const object. That's all. After that you have some const object rather than non-const one. Moreover there are cases where it is allowed to create a const copy of you initial non-const object. For example for the case of the function argument.Hitherto
Stanard says any attempt! There is no information about initial definition.Hitherto
@Alexey Malistov: No. An "object" refers to the actual region of storage occupied in memory (§1.7). Taking a const reference to a non-const object does not make the object const. Only in the case of a const reference parameter (not a const pointer parameter) is the compiler allowed to silently make a copy (§5.2.2/5); this is not the case here.Ullage
Are literals the only data that is originally declared as const?Tam
@AdamRosenfield: I tend to agree with Alexey Malistov because I managed to invoke UB via a const reference to a non-const object. I passed a reference to a member of the object to a function which used const_cast to modify the value. The compiler decided to pass a reference to a temporary on the stack instead, and thus the change was never made to the original member.Grogan
@DarkFalcon your observation doesn't contradict what AdamRosenfield said.Schopenhauerism
@Ruslan: Actually it does. "const_cast is safe only if you're casting a variable that was originally non-const" <-- That is what I did and that is what optimization broke. In other words, const_casting away const did not work correctly, even though the original variable was NOT const. It could be argued that this is an optimizer bug, but bug or not, it still caused a problem. The standard also seems to support the assertion that this should not be done.Grogan
@DarkFalcon see this phrase: Only in the case of a const reference parameter (not a const pointer parameter) is the compiler allowed to silently make a copy (§5.2.2/5) from his comment.Schopenhauerism
"However, if the original variable was in fact const, then using const_cast will result in undefined behavior" This statement is false.Millman
It's not UB to use const_cast to remove const from something that was initially declared const. But it is UB to actually try to write to that object. As long as you just read you are fine and the const_cast in itself does not cause UB. It's a horrible idea, but it's not inherently UB.Pharmacopsychosis
See https://mcmap.net/q/23051/-is-it-allowed-to-cast-away-const-on-a-const-defined-object-as-long-as-it-is-not-actually-modified and https://mcmap.net/q/23055/-is-it-safe-to-remove-const-via-const_cast-and-invoke-a-non-const-function-that-does-not-modify-the-resulting-object for quotes from standard confirming Lightness Races in Orbit's and Jesper Juhl's comments and disproving this answer.Hippocrates
D
36

I can think of two situations where const_cast is safe and useful (there may be other valid cases).

One is when you have a const instance, reference, or pointer, and you want to pass a pointer or reference to an API that is not const-correct, but that you're CERTAIN won't modify the object. You can const_cast the pointer and pass it to the API, trusting that it won't really change anything. For example:

void log(char* text);   // Won't change text -- just const-incorrect

void my_func(const std::string& message)
{
    log(const_cast<char*>(&message.c_str()));
}

The other is if you're using an older compiler that doesn't implement 'mutable', and you want to create a class that is logically const but not bitwise const. You can const_cast 'this' within a const method and modify members of your class.

class MyClass
{
    char cached_data[10000]; // should be mutable
    bool cache_dirty;        // should also be mutable

  public:

    char getData(int index) const
    {
        if (cache_dirty)
        {
          MyClass* thisptr = const_cast<MyClass*>(this);
          update_cache(thisptr->cached_data);
        }
        return cached_data[index];
    }
};
Dyanne answered 10/12, 2008 at 21:25 Comment(4)
This...doesn't seem to be answering this question. He asked if const_cast can cause undefined behavior, not what useful applications of it areFishwife
From the question: "Alternatively, when is it okay to use const_cast?"Dyanne
As in "when is it not undefined"; he's not looking for examples of when it's usefulFishwife
We can only stick on the letters of the question. Based on this, the presenting of an illustrative use of const_cast is a valid answer. There is no he in questions as the question alone is the subject.Fargone
C
26

I find it hard to believe that that's the only information you could find about const_cast. Quoting from the second Google hit:

If you cast away the constness of an object that has been explicitly declared as const, and attempt to modify it, the results are undefined.

However, if you cast away the constness of an object that has not been explicitly declared as const, you can modify it safely.

Cervantes answered 10/12, 2008 at 21:10 Comment(3)
Grrrreaat answer, combine this with this answer and you get the whole picture.Cyclotron
hmm. regarding the second statement in your answer, may i ask you how is there a "const"ness for an object which was not explicitly declared as const in the first place?.Dimer
There are lots of ways to make a non-const object be const, @Iam. For example, pass the object as a const-reference parameter. Or assign it to a pointer-to-const. Or use const_cast. Or call a const method on it.Cervantes
A
13

What Adam says. Another example where const_cast can be helpful:

struct sample {
    T& getT() { 
        return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    }

    const T& getT() const { 
       /* possibly much code here */
       return t; 
    }

    T t;
};

We first add const to the type this points to, then we call the const version of getT, and then we remove const from the return type, which is valid since t must be non-const (otherwise, the non-const version of getT couldn't have been called). This can be very useful if you got a large function body and you want to avoid redundant code.

A answered 10/12, 2008 at 21:17 Comment(3)
I would rather use static cast for the adding constness: static_cast<const sample*>(this). When I'm reading const_cast it means that the code is doing something potentially dangerous, so i try to avoid it's use when possible.Micronutrient
right, the first can be static_cast, or even be implicit_cast (of boost). i'll fix it using static cast. thanksA
I go back and forth on whether const_cast or static_cast is better. const_cast can only do what you want: change the cv-qualifiers. static_cast can 'silently' perform other operations that you don't intend. However, the first cast is entirely safe, and static_cast tends to be safer than const_cast. I think this is a situation where the const_cast communicates your intent better, but the static_cast communicates the safety of your actions better.Cooney
P
10

The short answer is no, it's not safe.

The long answer is that if you know enough to use it, then it should be safe.

When you're casting, what you are essentially saying is, "I know something the compiler doesn't know." In the case of const_cast, what you are saying is, "Even though this method takes in a non-const reference or pointer, I know that it won't change the parameter I pass it."

So if you do actually know what you are claiming to know in using the cast, then it's fine to use it.

Pergolesi answered 10/12, 2008 at 22:39 Comment(0)
O
3

You're destroying any chance at thread-safety, if you start modifying things that the compiler thought were const.

Obrien answered 10/12, 2008 at 21:16 Comment(4)
What? If you have immutable (const) objects, you can trivially share them amongst threads. The instant that a piece of your code casts away const-ness, you lose all of your thread safety! Why am I down-modded for this? sighObrien
Const is certainly a useful tool in making code thread-safe, but it gives no guarantees (except in the case of compile-time constants). Two examples: a const object may have mutable members, and having a const pointer to an object says nothing about whether the object itself could be changing.Zachery
I think this is a good answer because I didn't think about the compiler optimizer's feelings of trust and security in your use of the word const. const is trust. const_cast is breaking that trust :(Cyclotron
Concerning mutable and thread-safety: channel9.msdn.com/posts/…Pompano

© 2022 - 2024 — McMap. All rights reserved.