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
What are Legitimate uses of const_cast
You are right, uses of const_cast
often indicates a design flaw, or an API that is out of your control.
However, there is an exception, it's useful in the context of overloaded functions. I'm quoting an example from the book C++ Primer:
// 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;
}
This function takes and returns references to const string
. We can call the function on a pair of non-const 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 non-const 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, non-const arguments. Therefore, we know it is safe to cast that string back to a plain string&
in the return.
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
How to use const_cast?
You are not allowed to const_cast
variables that are actually const
. This results in undefined behavior. const_cast
is used to remove the const-ness from references and pointers that ultimately refer to something that is not const
.
So, this is allowed:
int i = 0;
const int& ref = i;
const int* ptr = &i;
const_cast<int&>(ref) = 3;
*const_cast<int*>(ptr) = 3;
It's allowed because i
, the object being assigned to, is not const
. The below is not allowed:
const int i = 0;
const int& ref = i;
const int* ptr = &i;
const_cast<int&>(ref) = 3;
*const_cast<int*>(ptr) = 3;
because here i
is const
and you are modifying it by assigning it a new value. The code will compile, but its behavior is undefined (which can mean anything from "it works just fine" to "the program will crash".)
You should initialize constant data members in the constructor's initializers instead of assigning them in the body of constructors:
Student(const Student & s)
: Person(p.getName(), p.getEmailAddress(), p.getBirthDate()),
school(0),
studentNumber(s.studentNumber)
{
// ...
}
When should static_cast, dynamic_cast, const_cast, and reinterpret_cast be used?
static_cast
is the first cast you should attempt to use. It does things like implicit conversions between types (such as int
to float
, or pointer to void*
), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast
isn't necessary, but it's important to note that the T(something)
syntax is equivalent to (T)something
and should be avoided (more on that later). A T(something, something_else)
is safe, however, and guaranteed to call the constructor.
static_cast
can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual
inheritance. It does not do checking, however, and it is undefined behavior to static_cast
down a hierarchy to a type that isn't actually the type of the object.
const_cast
can be used to remove or add const
to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast
). It is important to note that modifying a formerly const
value is only undefined if the original variable is const
; if you use it to take the const
off a reference to something that wasn't declared with const
, it is safe. This can be useful when overloading member functions based on const
, for instance. It can also be used to add const
to an object, such as to call a member function overload.
const_cast
also works similarly on volatile
, though that's less common.
dynamic_cast
is exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards – you can cast sideways or even up another chain. The dynamic_cast
will seek out the desired object and return it if possible. If it can't, it will return nullptr
in the case of a pointer, or throw std::bad_cast
in the case of a reference.
dynamic_cast
has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual
inheritance. It also can only go through public inheritance - it will always fail to travel through protected
or private
inheritance. This is rarely an issue, however, as such forms of inheritance are rare.
reinterpret_cast
is the most dangerous cast, and should be used very sparingly. It turns one type directly into another — such as casting the value from one pointer to another, or storing a pointer in an int
, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast
is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_cast
cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of a pointer to aligned data.
C-style cast and function-style cast are casts using (type)object
or type(object)
, respectively, and are functionally equivalent. They are defined as the first of the following which succeeds:
const_cast
static_cast
(though ignoring access restrictions)static_cast
(see above), thenconst_cast
reinterpret_cast
reinterpret_cast
, thenconst_cast
It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast
, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast
will succeed or reinterpret_cast
will fail. Even then, consider the longer, more explicit option.
C-style casts also ignore access control when performing a static_cast
, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.
Qt example const_cast
This is not undefined behavior. const_cast
is only undefined behavior if the object you start with is const and you modify the the object you get from the cast.
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
Is not going to modify const_cast<TreeItem*>(this)
since indexOf
takes a const T&
.
const_cast doesn't work c++?
const_cast
is normally used when/if you receive a const
pointer to an object that wasn't originally defined as const
. If (as in your case) the object was originally defined as const
, attempting to modify it causes undefined behavior. Without the const_cast
, the compiler won't let you even try to do that (the code won't compile).
A cast, however, tells the compiler you're sure you know what you're doing and it's really safe, so the compiler just needs to shut up and do what you told it instead of giving any error/warning messages like it might usually do. Unfortunately, in this case what you're doing is not really safe, but since you've told the compiler to shut up and do it, you won't get any warning about it (at least with most compilers).
As to what you should do, it comes down to deciding whether your k
is really const or not. If you really need to modify it, then you need to define it as a normal (non-const
) variable. If you want to ensure that only a small amount of specific code can modify it, then you could/can (for one possibility) make it private to a small class:
class my_int {
int k;
public:
my_int() : k(1) {}
do_mod() { k = 10; }
operator int() { return k; }
};
Now, do_mod
can modify k
directly. Other code can use a my_int
object as if it were an int
, but can't modify its value -- in essence, it acts like an rvalue.
In fairness, I should probably point out that if it really tries by doing some casting, other code can modify the value of k
. As Bjarne has said, C++'s protection mechanism is intended to prevent accidents, not intentional subversion.
C++ difference between adding const-ness with static_cast and const_cast of this object?
Assuming that the type of this
is A*
, there is no difference.
In general const_cast
can cast aways the const
specifier (from any level of indirection or template parameter)
static_cast<>
can cast a type to another if the target type is in the source's type hierarchy.
They cannot do each other's work.
The reason they both worked in your case is because you have introduced const-ness, as opposed to having taken it away (calling from the non-const version of the function the type of this
is A*
, no const). You could just as well have written
const A& tmp = *this;
tmp.Methodology();
and it would have worked without the need for any casting. The casting is used for convenience and terseness to not have to introduce a new variable.
Note: you can use static_cast<>
here as you know that you are casting to the right type. In other cases (when you cannot be sure) you need to use dynamic_cast<>
that does a runtime type check to ensure the conversion is valid
When is const_cast used in C++
I've only used const_cast on cases where I have to pass a const parameter to unmodifiable legacy code known to not modify the parameter, i.e. it is in practice const but the signature of the API/function call does not contain the const keyword.
How to properly cast char ** x to const char **
Allowing a cast from char**
to const char**
provides a loophole to modify a const char
or a const char*
.
Sample code:
const char c = 'A';
void foo(const char** ptr)
{
*ptr = &c; // Perfectly legal.
}
int main()
{
char* ptr = nullptr;
foo(&ptr); // When the function returns, ptr points to c, which is a const object.
*ptr = 'B'; // We have now modified c, which was meant to be a const object.
}
Hence, casting a char**
to const char**
is not a safe cast.
You can use
if(argc>1)
{
const char* ptr = argv[0];
print(&ptr);
}
for your code to compile without the cast-qual
warning.
If you need to pass more than just the first argument, you'll need to construct an array of const char*
and use it.
if(argc>1)
{
int N = <COMPUTE N FIRST>;
const char** ptr = new const char*[N];
for (int i = 0; i < N; ++i )
{
ptr[i] = argv[i];
}
print(ptr);
delete [] ptr; // Make sure to deallocate dynamically allocated memory.
}
Related Topics
Unique Hardware Id in MAC Os X
How to Detect Ip Address Change Programmatically in Linux
How to Define Several Include Path in Makefile
Differencebetween Imagemagick and Graphicsmagick
Converting a Variable Name to a String in C++
How Is Static Variable Initialization Implemented by the Compiler
Object Layout in Case of Virtual Functions and Multiple Inheritance
Constexpr VS. Static Const: Which One to Prefer
Pros and Cons of Using Nested C++ Classes and Enumerations
How to Use Valgrind with Python C++ Extensions
Difference Between Global Operator and Member Operator
Why Can't I Create a Vector of Lambdas (Of the Same Type) in C++11
Serializing and Deserializing JSON with Boost
Checking for Eof in String::Getline
Copy a Streambuf's Contents to a String
How to Automatically Avoiding Stepping into Certain Functions in Visual Studio