This is more of an academic question since I know to generally avoid const_cast.
But I was working on the exercise in Chapter 3, # 27 of Thinking in C++, Vol. 1.
Create a const array of double and a volatile array of double. Index
through each array and use const_cast to cast each element to
non-const and non-volatile, respectively, and assign a value to each
element.
I see how to const_cast single vars:
const int i = 0;
int* j = const_cast<int*>(&i);
*j = 1; // compiles and runs
But can't figure out how to get it to work with an array. The following compiles, but throws a 'bad access' exception, as if const is still there.
const int sz = 10;
const double cd[sz] {0,1,2,3,4,5,6,7,8,9};
volatile double vd[sz] {0,1,2,3,4,5,6,7,8,9};
double* cdp = const_cast<double*>(cd);
double* vdp = const_cast<double*>(vd);
cdp[0] = 99; // bad access error
Where have I got it wrong?
Please note:
const int i = 0;
int* j = const_cast<int*>(&i);
*j = 1; // UNDEFINED BEHAVIOR - modify actually const data
You are not allowed to modify an object by casting away constness that was initially declared as const. The compiler may place the contents of the object (or array, in your case) in read-only memory which is enforced at a lower level in the machine than the compiler. When you write, it may trigger a fault. If it's declared const, you must honor that forever, or get crashes as you're experiencing.
It's only ok to modify after casting away constness if the object was initially declared non-const. (That is, the constness was added later, perhaps as a reference parameter to a function.)
Let's rephrase your question into at least a valid situation for the sake of example.
// f() takes a reference to an array, but add constness
void f(const double(&arr)[10])
{
// Here it's ok to cast away constness and modify since the
// underlying object isn't declared const (though in general a
// function doesn't know that about its caller, except in
// constrained situations.)
double * array = const_cast<double*>(arr);
array[1] = 99;
}
int main()
{
// NOTE: array is NOT CONST
double arr[10] {0,1,2,3,4,5,6,7,8,9};
f(arr);
}
And this is fine.
Related
Below code is actually for an embedded system where you can modify global constant. currently we are trying to simulate some part in windows.
when we try to modify global constant in windows in vs 2005 it gives us stackoverflow exception and in vs 2015 it gives us access violation issue.
i am giving small code here to give idea. Here second modification will produce error.I just want to know why window do not allow such modification ?
Thanks in advance.
const int i = 5;
int main()
{
const int c = 10;
int* d = const_cast<int*>(&c);
*d = 20;
int* p = const_cast<int*>(&i);
*p = 20;
return 0;
}
Both code snippets invoke undefined behavior: const_cast<T> cannot be used to cast away const-ness of something that is actually const. It can be used only to cast away const-ness of something that is not const, but is presented as const to your code.
For example, if you pass a const pointer to a non-const variable to a function, it would be legal for that function to cast away const-ness, and make a modification:
void foo(const int* p) {
*(const_cast<int*>(p)) = 5;
}
However, if you were to pass a const pointer to something that is actually const, doing the same thing would trigger undefined behavior:
int main() {
int good = 123;
const int bad = 456;
foo(&good); // Works
foo(&bad); // Undefined behavior
}
The reason this "works" in your particular embedded system is that undefined behavior does not, unfortunately, mean that the corresponding piece of code must fail. It just so happens that your embedded toolchain places constants into modifiable memory, so const_cast-ing a const pointer gives you a valid address to write. Doing the same thing would fail on systems that place constants into write-protected memory.
I'm currently trying to learn some C++ and came across following unintuitive behavior. As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int a = 3;
const int* t = &a; //Why is this allowed? a is NOT const int
a = 4;
cout << *t << endl; //This does then print 4
//*t = 4; //Throws error.
return 0;
}
Can anyone explain why this is does compile?
const int* t just means you can't change the value t pointing to by t, nothing more. The original value might be changed, but it has nothing to do with t's responsibility.
If you want to ensure the value won't be changed, you should let t point to a const, such as
const int a = 3;
const int* t = &a;
And for this case, you can't make a int* pointer point to it.
int* t = &a; // error
As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
You cannot make that assumption in general, because t might point to a non-const object, such as in your example.
const int* t = &a; //Why is this allowed? a is NOT const int
Can anyone explain why this is does compile?
The rules of c++ allow the implicit conversion of T* to const T*. It is allowed, because it's very useful to have a pointer-to-const (or reference) to an non-const object. Pointer to const simply means that the object cannot be modified "through" the pointer. The object itself could be const, or non-const.
As an example of why it is useful, you could have some modifiable state as a private member of an object, and return const view to it so that others can observe, but not modify. A practical example of such is std::string::c_str(). It returns a const char* even though the internal buffer of the std::string is non-const.
As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
The answer is simple: the const keyword in a pointer type declaration does not mean 'it is constant' but rather 'you are not allowed to modify it'.
This is useful for example when you create a variable and then call another function to do something with it, but you want to forbid modification:
extern int countZerosInArray( const int *array, int arrayLen);
int myVariableArray[ 100 ];
// ... fill the array - i.e. modify it!
int noOfZeros = countZerosInArray(myVariableArray, 100);
The countZerosInArray function is told it has read-only access to the array, although the array itself of course is not constant.
const int* t = &a; // int* or const int* can assgin to const int*
I know this is probably a trivial question. What is the logic behind not being able to set a const pointer after its declaration? It's not as if allocating memory will change the starting address which is what the const refers to. So why can't this...
int* const p;
p = new int [10];
... be done... which also prohibits the passing of a const pointer into a function?
This is the entire purpose of const.
const stands for "constant", and means the object cannot be assigned to.
If you want the pointer to be a variable, don't make it const.
I suspect you were expecting your assignment to be allowed because it was the first ever assignment to that object. You were wrong! This is the purpose of initialisation, which you are not presently using.
I'm guessing you meant to write:
int* const p = new int[10];
But I worry that you have more fundamental misconceptions here. For example:
It's not as if allocating memory will change the starting address
Yes, it absolutely, completely will.
When your p comes into existence, it has an unspecified value. Its value is not a "starting address" that you can use.
Then you assign to it (though you ought to have initialised instead). It takes on the value equals to the pointer returned by new. That pointer has no relationship to anything previous in your code.
Allocating memory does change the address. For instance if we have
int * foo;
foo = new int[bar];
foo is uninitialized and has a garbage value. Then foo = new int[bar]; assigns to foo a new address that is the start of a block of bar ints.
Now when you have
int* const p;
The pointer is const so we cannot change it after it is initialized.
Short version
The way you are defining the pointer means that it is const for itself, so you cannot reassign it and you have actually to assign it along with its declaration.
Here more details about the const keyword, even though it is not specifically oriented to the use with the pointers.
Please even note that the following code should not compile for you are not assigning a value to the const pointer p:
int main() {
int * const p;
}
The same is true for the following one:
int main() {
int const i;
}
It doesn't depend on the fact that you are dealing with a pointer, instead it's how the const keyword actually works and should/can be used.
More details about const and pointers
Anyway, I didn't see your whole code and it looks to me that your intent is not to have a const pointer, instead in your case it could help having a pointer to const (but it mainly depends on your problem, so I can be wrong).
How to define them depends on your purposes, of course.
You can either define it as a const pointer or a pointer to a const value, the means of which are slightly different (of course, you can also define a pointer as a const pointer to a const value, that is an easily deducible consequence of the others above mentioned).
The first one indicates that the pointer itself cannot be reassigned, thus you have to assign it during the declaration and that's all.
The second one instead define a pointer that is reassignable, but you can assign it only addresses of const variables of the given type (or better, even if they are defined as non const, they will be treated as const when accessed through that pointer, with all the limitations of the case).
It follows a brief example of the types of const pointer and pointer to const above mentioned:
int main() {
int i;
// pointer to const int
int const *icp;
// const pointer to int
int * const cip = &i;
// const pointer to const int
int const * const cicp = &i;
// this one can be reassigned, of course
icp = &i;
}
Note also that int const and const int are interchangeable, so the declarations below are equivalent:
int const *p;
const int *p;
Obviously, this is not an exhaustive list. I've only tried to give you more details about how the const keyword can be used while defining a pointer and which are the intended means of those declarations.
int* const p;
declares p to be a pointer which cannot be changed, i.e. you cannot change where it points to once it is initialized. However, you can change the values it points to since the object type it points to is int.
int* const p = new int [10];
p = new int[20]; // Not OK
p[0] = 100; // OK
Contrast that with
int const* p = new int [10];
p = new int[20]; // OK. You can change where the pointer points to.
p[0] = 100; // Not OK. You cannot change the value of what p points to.
In a book I'm reading about C++ (C++ for Dummies) there is a section that says the following:
int nVar = 10;
int* pVar = &nVar;
const int* pcVar = pVar; // this is legal
int* pVar2 = pcVar; // this is not
The book then goes on to explain:
The assignment pcVar = pVar; is okay -- this is adding the const
restriction. The final assignment in the snippet is not allowed since
it attempts to remove the const-ness of pcVar
My question is why is the last line not "legal". I don't understand how that impedes on the "const-ness" of pcVar. Thanks.
const int *pcVar = pVar;
int *pVar2 = pcVar;
If pcVar is const int *, that implies that the int it points to may be const. (It isn't in this case, but it may be.) So if you assign pVar2, which is a non-const int *, it still allows the int it points to to be modified.
So if pcVar actually pointed to a const int, and you assign an int * to its address, then that int * pointer (pVar2 in this case) will allow you, by dereferencing, to modify it, and that's illegal (it's a constraint violation, so it invokes undefined behavior).
All the compiler knows is that pcVar is a const int*. That is, it points to a const int. Just because you made it point at a non-const int doesn't matter. For all the compiler knows, the pointer value could have changed at some point to point at a truly const int. Therefore, the compiler won't let you convert from a const int* back to a int* because it would be lying about the constness of the object it was pointing at.
For a simpler example, consider:
const int x;
const int* pc = x;
int* p = pc; // Illegal
Here, x truly is a const int. If you could do that third line, you could then access the const int object through p (by doing *pc) and modify it. That would be bad - x is const for a reason.
However, in the example you gave, since you know that the original object was non-const, you could use const_cast to force the compiler into trusting you:
int* pVar2 = const_cast<int*>(pcVar);
Note that this is only valid if you know for certain that the object is non-const.
It's just saying you can't create a non-const pointer from one that was const (at least, not without a const_cast).
The idea behind const is to have objects that cannot be modified by accident. Getting rid of const through a simple assignment would be quite dangerous, and would allow things like this:
void function(int* m) {
*m = 20;
}
int main() {
const int x = 10;
//Oops! x isn't constant inside function any more, and is now 20!
function(&x);
}
Also, please check out The Definitive C++ Book and Guide List, it has lots of great references (C++ for dummies doesn't quite make the cut).
Mixing const and non-const is illegal. The reason being, if you tell the compiler that one location's value is const and then use another pointer to modify that value, you have violated the const contract you made with the first element.
pcVar stays the same but pVar2 points to a non-const, const can be added but not taken away. The compiler does not look at the original nVar being non-const, only the attempt to assign a const to a non const. Otherwise you could get around the const and change the value.
int * pVar = &nVar;
*pVar = 4 //is legal
const int* pcVar = pVar; // this is legal
*pcVar = 3 // this is not legal, we said the value was const thus it can not be changed
int* pVar2 = pcVar; // this is not legal because...
*pVar2 = 3 -> *pcVar = 3
The second line
int pVar = &nVar;
is error.
g++ compiler says.
error: invalid conversion from ‘int*’ to ‘int’
Sample_Program-1
#include<iostream>
using namespace std ;
int main(){
const int i = 9;
int *j = const_cast<int*>(&i); //Ok
int *j = const_cast<int*>(i); //Error
}
Sample_Program-2
#include<iostream>
using namespace std ;
int main(){
const int i = 9;
int j = const_cast<int&>(i);//Ok
int j = const_cast<int>(i);//Error
}
I was just learning some c++ concept and met with the above 2 concepts . Can anyone please explain the concept i marked as error in the above 2 sample program ?
1) You are casting (const int*) to (int*). So because of const modifier you can't change the value that is placed at that address(pointer point to some address in memory). When you cast it to (int*) compiler will allow change data at that address.
2) You are trying to cast (const int) to pointer to int (int*). (int) and (int*) are different types. This is the same as ask const_cast to cast string to float. The const_cast operator can't change the type of the variable. To make such things you should look to static_cast or reinterpret_cast.
3) You cast const int to reference to int and assign the value to int(you simply copied the value to a new variable). This is probably not exactly you wanted, because changing j in this case doesn't change i. You can create a reference to int instead of j and then you can change the value of i.
4) I don't understand what you are trying to do here. The idea of the const_cast is to remove the const protection on object. So this operation is possible only on pointers and references. You don't need any cast to copy const int to int. But you can't change the value of i until you take pointer or reference and remove the protection.
Conclusion.Removing a const is a bad style of programming. Assume you wrote a library where a function has const int* argument. The user of your library will be sure that his int won't change but you changed it and he lost the data he needed.
When you write
int *j = const_cast<int*>(i);
you are trying to convert 'i' to a pointer. const_cast is not meant to be used for changing the data type.
maybe you meant
int *j = const_cast<int*>(&i);
Here is the first statement explained:
[cast to non-const int pointer] ( [get a pointer to 'i' (const)] );
const_cast<int*> ( &i );
Here is the second statement explained:
[cast to non-const int pointer] ( [get value of 'i'] );
const_cast<int*> ( i );
The error is because an integer value is not a pointer value, and so, the const_cast cannot do that cast. It can only map pointers to pointers, or references to references.
Here is the third statement explained:
[cast to non-const int reference] ( [implicitly get a reference to 'i' (const)] );
const_cast< int& > ( i );
Here is the second statement explained:
[cast to non-const int value] ( [get value of 'i' (const)] );
const_cast< int > ( i );
The error is because the const_cast cannot be used to cast between values, only between pointers or references. For values, we talk about "conversions" not casts. As in:
int i_nc = i; // OK: no need for const-cast since the value is copied.
A conversion is a method to copy the value of an object of one type into an object of another type. Casting operators don't make sense for that purpose.