51

As a common rule, it is very often considered a bad practice to use const_cast<>() in C++ code as it reveals (most of the time) a flaw in the design.

While I totally agree with this, I however wonder what are the cases were using const_cast<>() is ok and the only solution.

Could you guys please give me some examples you know/you encountered ?

Thank you very much.

ereOn
  • 53,676
  • 39
  • 161
  • 238
  • Since I'm still getting notifications for this, let me say that I think that the accepter answer should not be mine, but the highest voted one, since it provides the only acceptable (IMO) use of `const_cast` that viewers may care about. – Alexandre C. May 10 '18 at 11:33

8 Answers8

35

it is pretty much designed to be only used with legacy APIs that are not const correct i.e. with a function you can't change that has non const interface but doesn't actually mutate anything on the interface

jk.
  • 13,817
  • 5
  • 37
  • 50
  • Also C APIs that share the same structure for reading and writing, like `readv`/`writev` where `struct iov` has `void* data` rather than `void const* data` because `readv` writes to it but `writev` doesn't. –  Aug 13 '21 at 18:38
23

Like others have said, its primary purpose is to remove const from objects in order to pass to non-const correct functions you know won't modify the argument.

There is a trick (by Meyers?) to avoid code duplication, and it goes like this:

struct foo
{
    const return_type& get(void) const
    {
        // fancy pants code that you definitely
        // don't want to repeat

        return theValue; // and got it
    }

    return_type& get(void)
    {
        // well-defined: Add const to *this,
        // call the const version, then
        // const-cast to remove const (because
        // *this is non-const, this is ok)
        return const_cast<return_type&>(static_cast<const foo&>(*this).get());
    }
};
Gurgadurgen
  • 408
  • 3
  • 13
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 11
    I think this trick is almost always worse than duplicating the contents of `get() const` in `get()`. In the cases where this is better than copy and paste, a template helper (instantiated once for const and once for non-const) would be even better, since it would allow the compiler to verify that the fancy pants code really does return something modifiable in the case where `this` is modifiable. It might not, it might sometimes return a reference to a `const` global variable, so this trick forces you to manually verify the const-correctness of fancy pants code. Bad. – Steve Jessop Apr 20 '10 at 08:29
  • 1
    @Steve: I'd rather do this copy paste. In the special case where this trick won't work, don't use it. – GManNickG Apr 20 '10 at 08:38
  • 2
    What if the "fancy pants" code is 0 lines, and `get` just returns a data member? Would you avoid copy-paste then? My claim is that there are no good cases for this trick. Either the code is simple enough to copy-paste, or else it is too complex to analyse manually for const-correctness. There's no middle ground which is too much to copy, but little enough that you don't want automated const-correctness. In Meyer's example IIRC the fancy-pants code is a bounds-check: so put the check in a helper function, same way we normally share code ;-) – Steve Jessop Apr 20 '10 at 09:56
  • 1
    "If it won't work, don't use it" is all very well, but requires manual const-analysis to figure out whether it will work or not. If it's OK to do manual const-analysis, why are we bothering with const and non-const versions of member functions in the first place? – Steve Jessop Apr 20 '10 at 09:59
  • 1
    @Steve Jessop: I don't think I agree with you about copy/paste. Even if the code is trivial, you're still using repetition and as such will probably forget to update both version of the code as is always the problem with repetition. I agree that loosing "perfect" (well there is still other loopholes possible) const-correctness is less than great but I think I still prefer this in most case to repetition (the possibility of error because of the const-correctness is, for me, lower than forgetting about updating repetitive code at more than one place). – n1ckp Feb 15 '11 at 17:58
  • 2
    @n1ck: The functions would be adjacent, but sure there is a risk that someone will e.g. go in and add a bounds check to one but forget the other. If I was worried about that I would have them each call a common template helper function, thus eliminating *both* risks. It's not an either-or situation. Ultimately this trick implements one thing in terms of another thing which it logically *cannot* in general be implemented in terms of. The call from non-const version to const is valid only because of implementation details of the const (it never returns const objects). That's why I don't like it. – Steve Jessop Feb 16 '11 at 11:40
  • @Steve Jessop: My point was that you said to prefer code duplication over the const trick (for small amount of code) and, at that, I said that I prefer it to the code duplication about anytime. You're point about using a template function is very interesting though and I will check if I can adapt my code not to loose the const correctness where i used to use this trick in my code but I'm not sure that it can always be done as easily as you say. If it can though I would be very happy, like I said, I only said that it was better than code duplication, not your other point. – n1ckp Feb 16 '11 at 14:05
  • 3
    @n1ck: OK. A template helper looks something like `template RET &get_helper(SELF &self) { /* fancy pants code */ return self.theValue; }`. Then call it as `get_helper(*this)` from the const `get` and `get_helper(*this)` from the non-const. – Steve Jessop Feb 16 '11 at 15:20
  • @Steve Jessop: I don't know where you got in my message that I wouldn't know how to write a basic template function but I find it borderline insulting. Like I said I will come back to you when I'm done converting my code as it IS more complicated than your little function (but nothing requiring anything extraordinary changes, so I think it could probably work in all the case). I would still advocate to use this trick over code duplication though (say if the template function is deemed too much work to do for the moment) but otherwise the template function DO seem to do the job better. – n1ckp Feb 17 '11 at 11:38
  • 2
    @n1ck: "I find it borderline insulting" - how do you live on the internet? I was trying to convey (a) the fact that you const-qualify two template parameters, and (b) that there's a simple transformation from GMan's preferred code to mine, that doesn't really depend on the contents of the getter. I (insincerely) apologise for the fact that in doing so I had to demonstrate use of the keyword `this`, which you no doubt are also already familiar with ;-). That's just the simplistic approach anyway, in GMan's example you can easily get rid of one of the template parameters with a C++0x `decltype`. – Steve Jessop Feb 17 '11 at 11:44
  • @Steve Jessop: Hugh ... If I said I found it insulting was because I though from my initial message it was clear that I knew how to do a template function to get rid of the const_cast and as such, your reply didn't made any sense. I reread my message and I have to appologize: it was not as clear as I though it was. Still you're last message demonstrate that you still think I don't know what I'm saying and I wonder if you tried to read my message as a whole or were just trying to feel smart. In short, all you're talk is things I knew and you didn't need to clarify those things to me, ty. – n1ckp Feb 17 '11 at 13:26
  • 1
    The `C++ Core Guidelines` mention the const/mutable getter in one of the examples for guideline `ES.50: Don't cast away const`. But they advice to use a templated helper function that deduces `const`. https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#example-211 – Synck Nov 25 '19 at 12:12
22

const_cast is also used to remove volatile modifiers, as put into practice in this (controversed) article:

http://www.drdobbs.com/184403766

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
11

I agree with your statement that its normal use is because you need to hide a 'design flaw'.

IME one of the typical usage scenarios is when you try to interface C++ to existing C code. A lot of existing C code takes C strings as char * even when the string is not modified whereas they're usually represented as something that converts to a const char * in C++. That's an impedance mismatch between the two languages that you would normally solve by using a const_cast. Of course you'd better be very sure that the code you're interfacing with doesn't get any cute ideas about modifying the data that's being passed in.

I would say that it's a code smells in newly written code, but for interfacing with older C and C++ code, it's an necessary evil. That said, I would be extremely wary of code that requires const_cast for any non-POD objects as that is normally a problem that should be solved at the design level and not the code level.

Timo Geusch
  • 24,095
  • 5
  • 52
  • 70
  • Arguably it's not a necessary evil, because normally you can just make a mutable copy of a const char *. Of course, it would be nice if the language had some syntactic sugar for that, especially for string literals. – Fax Jul 04 '19 at 12:31
8

One legitimate use (in my opinion) is with std::set iterators. They are always const, in order to prevent changing the key used in the set. Changing the key would break the internal structure of the set and cause undefined behavior.

However, as long as the key doesn't change it's safe to change other data in the object.

Let's say you have an std::set like this:

std::set<MyObject> some_set;

And a class like this:

class MyObject {
    public:
        MyObject(const std::string &key)
            : key_(key) {}

        bool operator<(const MyObject &other) const {
            return key_ < other.key_;
        }

    private:
        // ...
        // <some other data>
        // ...

        const std::string key_;
};

In the above example, the key is already const, so even if you modify the object, you cannot break the internal structure of the set.

Normally you can only get a const reference out of a set iterator:

const MyObject &object = *some_set_iterator;

But since the key is const, it's safe to const_cast the dereferenced iterator:

MyObject &object = const_cast<MyObject &>(*some_set_iterator);
Kankaristo
  • 2,515
  • 2
  • 20
  • 16
1

One very legitimate use of this is when you have both a const and non const api (for const and non const objects respectively) as in

class Bar {
   const SomeType& foo() const; 
   SomeType& foo();
}

Then since we don't want to duplicate the code in both functions we often use

class Bar {
   SomeType& foo() {
      //Actual implementation 
   }
   const SomeType& foo() const {
        return const_cast<Bar*>(this)->foo();
   }
};

This is of course assuming that foo does not do something that violates the const semantics.

Jasmeet
  • 2,324
  • 16
  • 9
  • 2
    You have that backwards, and it may lead to undefined behavior. – GManNickG Apr 20 '10 at 08:14
  • 3
    The concern is that the non-const version of `foo` might modify `this`, and so it is "unsafe" to call it on a const object that you've cast to non-const. It's "safe" to call a const member function on a non-const object, so GMan's version is preferable. However, GMan's version also may lead to undefined behaviour when the client modifies the returned value, as I commented on his answer. – Steve Jessop Apr 20 '10 at 08:36
  • @Steve Jessop, my last sentence states "This is of course assuming that foo does not do something that violates the const semantics.". That was the assumption. Although I agree you can do it both ways. @Dennis Zickefoose - I originally thought that you were implying that just casting away constness leads to undefined behavior, which is clearly not true. However on reading your comment again, it seems that you are saying the same thing as Steve Jessop, so I guess I have the same answer. – Jasmeet Apr 20 '10 at 08:46
  • 3
    "That was the assumption". Sure, and GMan (along with Scott Meyers) point out that this is not a wise assumption to make, nor a necessary one. – Steve Jessop Apr 20 '10 at 09:52
0

Yes of course, when your calling code that you can't modify and isn't const correct. It should be noted that you should only use it with calls to functions that you know for certain won't modify your data!

Ivan
  • 1,735
  • 1
  • 17
  • 26
0

There is an example of const_cast usage in c++ primer(5th edition) book. Below function returns reference to const string

// return a reference to the shorter of two strings
const string &shorterString(const string &s1, const string
&s2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}

The book then mentions the case when we want a non const reference.

We can call the function on a pair of nonconst string arguments, but we’ll get a reference to a const string as the result. We might want to have a version of shorterString that, when given nonconst arguments, would yield a plain reference. We can write this version of our function using a const_cast:

string &shorterString(string &s1, string &s2)
{
    auto &r = shorterString(const_cast<const string&>(s1),
                            const_cast<const string&>(s2));
    return const_cast<string&>(r);
}

This version calls the const version of shorterString by casting its arguments to references to const. That function returns a reference to a const string, which we know is bound to one of our original, nonconst arguments. Therefore, we know it is safe to cast that string back to a plain string& in the return.

According to the book, it should be used if we know it is safe to cast.

bornfree
  • 2,308
  • 1
  • 23
  • 33