96

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?

msc
  • 33,420
  • 29
  • 119
  • 214
Mag Roader
  • 6,850
  • 8
  • 32
  • 27
  • 4
    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_cast`ing 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. – underscore_d Dec 22 '15 at 01:39
  • 2
    @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?](//stackoverflow.com/q/54504247) – Peter Cordes Feb 05 '19 at 03:30
  • 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?](https://stackoverflow.com/questions/54504247/is-it-allowed-to-cast-away-const-on-a-const-defined-object-as-long-as-it-is-not) – Thomas Weller Mar 09 '23 at 17:35

6 Answers6

93

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
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • 11
    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. – Alexey Malistov Nov 08 '10 at 15:12
  • 23
    @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. – Puppy Nov 09 '10 at 16:53
  • @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. – Alexey Malistov Nov 12 '10 at 10:23
  • 1
    Stanard says **any attempt**! There is no information about initial definition. – Alexey Malistov Nov 12 '10 at 10:29
  • 45
    @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. – Adam Rosenfield Nov 12 '10 at 16:02
  • 2
    Are literals the only data that is originally declared as const? – Tahlil Jun 25 '14 at 04:37
  • 1
    @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. – Dark Falcon May 15 '15 at 19:48
  • @DarkFalcon your observation doesn't contradict what AdamRosenfield said. – Ruslan Oct 14 '15 at 18:35
  • 1
    @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_cast`ing 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. – Dark Falcon Oct 14 '15 at 19:19
  • 4
    @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. – Ruslan Oct 15 '15 at 04:00
  • 9
    _"However, if the original variable was in fact const, then using const_cast will result in undefined behavior"_ This statement is false. – Lightness Races in Orbit Feb 03 '19 at 15:30
  • 12
    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. – Jesper Juhl Feb 03 '19 at 16:13
  • See https://stackoverflow.com/a/54504302/9204 and https://stackoverflow.com/a/29883695/9204 for quotes from standard confirming Lightness Races in Orbit's and Jesper Juhl's comments and disproving this answer. – Alexey Romanov Sep 20 '19 at 10:42
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];
    }
};
Fred Larson
  • 60,987
  • 18
  • 112
  • 174
  • This...doesn't seem to be answering this question. He asked if `const_cast` can cause undefined behavior, not what useful applications of it are – Michael Mrozek May 21 '14 at 15:21
  • 15
    From the question: "Alternatively, when is it okay to use const_cast?" – Fred Larson May 21 '14 at 15:32
  • As in "when is it not undefined"; he's not looking for examples of when it's useful – Michael Mrozek May 21 '14 at 15:40
  • 2
    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. – daparic Aug 14 '20 at 03:05
25

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.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Grrrreaat answer, combine this with [this answer](http://stackoverflow.com/questions/357600/is-const-cast-safe/357640#357640) and you get the whole picture. – bobobobo Sep 04 '11 at 14:36
  • 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?. – hAcKnRoCk Apr 16 '12 at 11:40
  • 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. – Rob Kennedy Apr 16 '12 at 13:15
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.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 3
    I would rather use static cast for the adding constness: static_cast(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. – mfazekas Jan 09 '09 at 07:08
  • 1
    right, the first can be static_cast, or even be implicit_cast (of boost). i'll fix it using static cast. thanks – Johannes Schaub - litb Jan 09 '09 at 11:56
  • 3
    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. – David Stone Feb 21 '13 at 17:21
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.

JohnMcG
  • 8,709
  • 6
  • 42
  • 49
3

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

Matt Cruikshank
  • 2,932
  • 21
  • 24
  • 1
    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? *sigh* – Matt Cruikshank Dec 10 '08 at 22:53
  • 9
    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. – James Hopkin Dec 11 '08 at 09:29
  • 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 :( – bobobobo Sep 04 '11 at 14:35
  • 1
    Concerning mutable and thread-safety: http://channel9.msdn.com/posts/C-and-Beyond-2012-Herb-Sutter-You-dont-know-blank-and-blank – MFH Jan 21 '13 at 20:25