C++: Why Is Const_Cast Evil

C++: Why is const_cast evil?

Because you're thwarting the purpose of const, which is to keep you from modifying the argument. So if you cast away the constness of something, it's pointless and bloating your code, and it lets you break promises that you made to the user of the function that you won't modify the argument.

In addition, using const_cast can cause undefined behaviour. Consider this code:

SysOscillatorBase<int> src;
const SysOscillatorBase<int> src2;

...

aFieldTransformer.setOscillator(src);
aFieldTransformer.setOscillator(src2);

In the first call, all is well. You can cast away the constness of an object that is not really const and modify it fine. However, in the second call, in setOscillator you are casting away the constness of a truly const object. If you ever happen to modify that object in there anywhere, you are causing undefined behaviour by modifying an object that really is const. Since you can't tell whether an object marked const is really const where it was declared, you should just never use const_cast unless you are sure you'll never ever mutate the object ever. And if you won't, what's the point?

In your example code, you're storing a non-const pointer to an object that might be const, which indicates you intend to mutate the object (else why not just store a pointer to const?). That might cause undefined behaviour.

Also, doing it that way lets people pass a temporary to your function:

blah.setOscillator(SysOscillatorBase<int>()); // compiles

And then you're storing a pointer to a temporary which will be invalid when the function returns1. You don't have this problem if you take a non-const reference.

On the other hand, if I don't use const_cast, the code won't compile.

Then change your code, don't add a cast to make it work. The compiler is not compiling it for a reason. Now that you know the reasons, you can make your vector hold pointers to const instead of casting a square hole into a round one to fit your peg.

So, all around, it would be better to just have your method accept a non-const reference instead, and using const_cast is almost never a good idea.


1 Actually when the expression in which the function was called ends.

Is const_cast safe?

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

Correct usage(s) of const_cast

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

http://www.drdobbs.com/184403766

C++ const cast, unsure if this is secure

As an example of evil behavior: the interaction with gcc's Copy On Write implementation.

#include <string>
#include <iostream>

int main() {
std::string const original = "Hello, World!";
std::string copy = original;

char* c = const_cast<char*>(copy.c_str());
c[0] = 'J';

std::cout << original << "\n";
}

In action at ideone.

Jello, World!

The issue ? As the name implies, gcc's implementation of std::string uses a ref-counted shared buffer under the cover. When a string is modified, the implementation will neatly check if the buffer is shared at the moment, and if it is, copy it before modifying it, ensuring that other strings sharing this buffer are not affected by the new write (thus the name, copy on write).

Now, with your evil program, you access the shared buffer via a const-method (promising not to modify anything), but you do modify it!

Note that with MSVC's implementation, which does not use Copy On Write, the behavior would be different ("Hello, World!" would be correctly printed).

This is exactly the essence of Undefined Behavior.

const_cast VS mutable ? any difference?

const_cast cannot cancel constness of an object. const_cast can only remove constness from an access path to an object. Access path is a pointer or a reference to an object. Removing the constness from the access path has absolutely no effect on the object itself. Even if you use const_cast to remove the constness of the access path, that still does not necessarily give you the permission to modify the object. Whether you can do it or not still depends on the object itself. If it is const, you are not allowed to modify it and any attempts to do so will result in undefined behavior.

For example, this illustrates the intended use of const_cast

  int i = 5; // non-constant object
const int *p = &i; // `p` is a const access path to `i`

// Since we know that `i` is not a const, we can remove constness...
int *q = const_cast<int *>(p);
// ... and legally modify `i`
*q = 10;
// Now `i` is 10

The only reason the above is legal and valid is the fact that i is actually a non-constant object, and we know about it.

If the original object was really constant, then the above code would produce undefined behavior:

  const int j = 5; // constant object
const int *p = &j; // `p` is a const access path to `j`

int *q = const_cast<int *>(p); // `q` is a non-const access path to `j`
*q = 10; // UNDEFINED BEHAVIOR !!!

C++ language does not allow you to modify constant objects and const_cast is completely powerless here, regardless of how you use it.

mutable is a completely different thing. mutable creates a data filed that can be legally modified even if the containing object is declared const. In that sense mutable does allow you to modify [some designated parts of] constant objects. const_cast, on the other hand, can't do anything like that.

const_cast failing in c++

Two questions:

  1. What are you trying to acheive here?
  2. How much control have you got over the code? (i.e. what are you able to change?)

Without wishing to be unkind I would honestly say that it might be better to start again. There are a couple of issues I would have with this code:

Firstly, the Singleton pattern should ensure that only one of a specific object is ever created, therefore it is usually returned by pointer, reference or some derivative thereof (i.e. boost shared pointer etc.) It need not necessarily be const though and the fact that it is here indicates that the author did not intend it to be used in a non-const way.

Second, you're then passing this object by reference into a function. No need. That's the one of the major features (and drawbacks) of the singleton pattern: You can access it from anywhere. So you could just as easily write:

SomeClass::Construct()
{
IListener* pListener = const_cast<IListener*>(*Singleton::GetInstance());
}

Although this still doesn't really help you. One thing it does do is make your interface a bit clearer. You see, when you write SomeClass::Construct(const IListener&listener) anyone reading your could reasonably imply that listener is treated as const within the function and by using const_cast, you've broken that implied contract. This is a very good reason that you should not use const_cast - at least not in these circumstances.

The fundamental question that you need to ask yourself is when your IListener is const, why do you need to use it in a non-const way within Construct? Either the singleton should not return a const object or your function should not need it to be non-const.

This is a design issue that you need to sort out before you take any further steps.

Is const a lie? (since const can be cast away)

const is a promise you make to the compiler, not something it guarantees you.

For example,

void const_is_a_lie(const int* n)
{
*((int*) n) = 0;
}

#include <stdio.h>
int main()
{
const int n = 1;
const_is_a_lie(&n);
printf("%d", n);
return 0;
}

Output shown at http://ideone.com/Ejogb is

1

Because of the const, the compiler is allowed to assume that the value won't change, and therefore it can skip rereading it, if that would make the program faster.

In this case, since const_is_a_lie() violates its contract, weird things happen. Don't violate the contract. And be glad that the compiler gives you help keeping the contract. Casts are evil.

C++. Why I can't compile this code? What is wrong with removing constness using const_cast?

const_cast is used to convert from pointers or references to const objects, to their non-const equivalents. However, you can't use them to modify the object they refer to if the object itself is const. There is no valid way to modify m_Size; if you want to modify it, then don't declare it const.

You do not need a cast to assign to the pointer, since the pointer itself is not const:

this->m_Memory = srcObj->GetAddress();

If you did want the pointer itself to be const, then the const would come after the *:

char * const m_Address;

and, as with the const size_t, you wouldn't be able to reassign it.

As the error says, you can convert a const value into a non-const temporary copy of that value without a cast; but you couldn't assign to that temporary.

When we need to remove constness of a variable , usage example?

Mostly you should not do it, but some time you are stuck with a third party library which expects a char* ,but in your implementation you have the field marked as const , then you need to temporarily cast away the constness then make the function call.



Related Topics



Leave a reply



Submit