My problem is, why first part of the code does not work while the second one works. Non-const pointer should modify the const value using the const_cast previously but with integers this trick does not work. Could you explain why that happens?
const int i = 5;
cout << i << endl; //output: 5
int *ptr_i = const_cast<int*>(&i);
*ptr_i = 100;
cout << i << endl; //output : 5
const double d = 5;
cout << d << endl; //output : 5
double *ptr_d = const_cast<double*>(&d);
*ptr_d = 100.;
cout << d << endl; //output : 100
Modifying a const variable is undefined behaviour:
n4296 ยง7.1.6.1/4
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.
const_cast is generally for communicating with non-const-correct APIs or casting away volatile qualifiers; it shouldn't be used like this.
Non-const pointer should modify the const value using the const_cast previously but with integers this trick does not work.
No, non-const pointer modifying the const value is undefined behavior. It is not supposed to work.
Could you explain why that happens?
Since this is UB, the compiler is free to do anything at all here, and "anything at all" means the code will happen to work in the case of int only (at least, for your compiler).
TLDR: undefined behavior is undefined.
Related
After coming across something similar in a co-worker's code, I'm having trouble understanding why/how this code executes without compiler warnings or errors.
#include <iostream>
int main (void)
{
unsigned int u = 42;
const int& s = u;
std::cout << "u=" << u << " s=" << s << "\n";
u = 6 * 9;
std::cout << "u=" << u << " s=" << s << "\n";
}
Output:
u=42 s=42
u=54 s=42
First, I expect the compiler to issue some kind of diagnostic when I mix signed/unsigned integers like this. Certainly it does if I attempt to compare with <. That's one thing that confuses me.
Second, I'm not sure how the second line of output is generated. I expected the value of s to be 54. How does this work? Is the compiler creating an anonymous, automatic signed integer variable, assigning the value of u, and pointing the reference s at that value? Or is it doing something else, like changing s from a reference to a plain integer variable?
References can't bind to objects with different type directly. Given const int& s = u;, u is implicitly converted to int firstly, which is a temporary, a brand-new object and then s binds to the temporary int. (Lvalue-references to const (and rvalue-references) could bind to temporaries.) The lifetime of the temporary is prolonged to the lifetime of s, i.e. it'll be destroyed when get out of main.
I understand that const_cast works with pointers and references.
I'm assuming that the input to const_cast should be a pointer or reference. I want to know why it doesn't remove the constness if the input is a pointer/reference to a const int?
The following code works as expected.
const_cast with multilevel pointers
int main()
{
using std::cout;
#define endl '\n'
const int * ip = new int(123);
const int * ptr = ip;
*const_cast<int*>(ptr) = 321;
cout << "*ip: " << *ip << endl; // value of *ip is changed to 321
}
But when I try a pointer to const int or reference to const int, the value doesn't seem to change.
const_cast with reference to const int
int main()
{
using std::cout;
#define endl '\n'
const int i = 123;
const int & ri = i;
const_cast<int&>(ri) = 321;
cout << "i: " << i << endl; // value in 'i' is 123
}
const_cast with pointer to const int
int main()
{
using std::cout;
#define endl '\n'
const int i = 123;
const int * ri = &i;
*const_cast<int*>(ri) = 321;
cout << "i: " << i << endl; // value in 'i' is 123
}
(1) works as expected, but I'm unable to comprehend why (2) & (3) don't work the way I think though the input to the const_cast is a pointer/reference.
Please help me understand the philosophy behind this. Thanks.
There are two kinds of constness.
Constness of an object is an inherent property of an object. It cannot be changed.
Think of a page in a printed book. It can be viewed as a string of characters, and it cannot be changed. It says what it says and that's it. So it's a const string.
Now think of a blackboard. It may have something written on it. You can wipe that and write something else. So the blackboard is a non-const string.
The other kind of constness is pointer and reference constness. This constness is not an inherent property of the pointed-to object, but a permission. It says you are not allowed to modify the object through this pointer. It says nothing about whether the object itself can be modified.
So if you have a const pointer, you don't necessarily know what it really points to. Maybe it's a book page. Maybe it's a blackboard. The pointer doesn't tell.
Now if you do know somehow that it is indeed a blackboard, you can be nasty and demand permission to go ahead and change what's written on it. That's what const_cast does. It gives you permission to do something.
What happens if you demand permission to modify a string, and it turns out to be a printed page? You get your permission, you go ahead and wipe it... and... What exactly happens is undefined. Perhaps nothing at all. Perhaps the print is smeared and you can neither recognise the original string nor write anything on top. Perhaps your world explodes to little pieces. You can try and see, but there's no guarantee the same thing will happen tomorrow.
(2) and (3) has the same principle, so I'll talk about (2) only.
The line
const_cast<int&>(ri) = 321;
has undefined behavior.
You cannot modify a const object according to the standard, not even with const_cast. If you remove const from a pointer/reference, and modify the pointed/referenced object, the pointed/referenced object must not been declared as const in the first place.
const_cast should be used only, when you have a const pointer to something for some reason, and you know that something is not declared as const.
Modifying the constant via the const_cast is undefined behaviour.
The compiler sees that you are trying to print a constant variable, knows it can never change so compiles:
cout << "i: " << i << endl;
to:
cout << "i: " << 123 << endl;
see: https://godbolt.org/z/bYb0mx. With optimisations enabled it optimises your code to just printing 123: https://godbolt.org/z/4Ttlmj.
Ultimately compilers make assumptions in order to create faster/smaller code, if you enter the realms of undefined behaviour some of those assumptions may be incorrect and produce surprising results.
I have a big confusion about how a c++ compiler treating with a const variable
const int constfunc()
{
return 7;
}
const int u1 = constfunc();
int* pu1 = const_cast<int*>(&u1);
*pu1 = 10;
cout << u1 << endl;
cout << *pu1 <<endl;
The result of precending code is:
10
10
While I try to assign a literal value to u1 variable neither than a const function, I mean:
const int u1 = 7;
The result will be changed:
7
10
I have really two confusions:
1- I made a little change but the result different?
2- As I know a const_cast remove a const restriction on a const pointers which point to none const variables, but in my sample1 I can modify value of const variable "u1"?
int* pu1 = const_cast<int*>(&u1);
removes the const restriction.
*pu1 = 10;
calls for undefined behavior.
Thus the result of
cout << u1 << endl;
cout << *pu1 <<endl;
won't be predictable by the means of c++ standards.
Here's a lil' illustration how it goes:
So just write clean code and don't try to undermine compiler errors using cast expressions, unless you're a 100% sure what you are doing.
This confusion is related to a compiler's optimization, i.e:
const int u1 = 7;
This tell compiler the u1 variable can't be change and can be evaluated at compile time, so you can replace each u1 in the code by it's value (7), i.e printing code will be modified by the compiler as:
cout << 7 << endl;
When you call an address of the u1 variable:
int* pu1 = const_cast<int*>(&u1);
The compiler will automatically create a storage for const variable and put it's info in a symbol table, so the result is 7 10.
Another case, when you write:
const int constfunc()
{
return 7;
}
const int u1 = constfunc();
This tells the compiler the u1 variable can't be change and u1 will be evaluated at runtime time neither than compile time, because it's rvalue is result of the constfunc execution, so no optimization here and the u1 variable will allocate a memory storage and printing u1 code will still as it to fetch its value from a memory:
cout << u1 << endl;
Note1: Put constexpr specifier to the constfunc function will enforce the compiler to evaluate the u1 variable at compile time neither run time so the result will be changed as 7 10.
Note2: Removing const restriction by const_cast may be undefined behavior
How is it possible that the value of *p and the value of DIM are different but the have the same address in memory?
const int DIM=9;
const int *p = &DIM;
* (int *) p = 18; //like const_cast
cout<< &DIM <<" "<< p << '\n';
cout << DIM << " " << *p << '\n';
You're changing the value of a const variable, which is undefined behavior. Literally anything could happen when you do this, including your program crashing, your computer exploding, ...
If a variable is supposed to change, don't make it const. The compiler is free to optimise away accesses to const variables, so even if you found a successful way to change the value in memory, your code might not even be accessing the original memory location.
It is a compiler optimization. Given that DIM is a constant, the compiler could have substituted its known value.
The code below does what you meant to do... as mentioned in other posts, if you mean to change the value of an variable, do not define it as const
#include <stdio.h>
int main()
{
int d= 9;
int *p_d=&d;
*p_d=18;
printf("d=%d\np_d=%d\n",d,*p_d);
return 0;
}
This code prints
d=18
p_d=18
I'm trying to compile the following piece of code, but I'm getting a C2440 (visual studio) error. I've tried looking at other resources for help, but I can't find a good explanation.
int main()
{
int a = 100;
SomeFunction(&a);
}
void SomeFunction(const int* value)
{
//This line of code gives me the error.
int* variable = value;
cout << "Value is " << *Variable << " end" << endl;
}
I know I can solve this problem by using int* variable = const_cast<int*> (value);, but I still don't understand why the above code is causing a problem.
The error's quite clear - a pointer conversion can't remove a const qualifier; otherwise, you could violate the constness:
int* variable = value; // Not allowed - but if it were...
*variable = 42; // BOOM! changed a constant.
If you don't want to be able to change the value being pointed at, then keep it const
const int* variable = value;
If you do want to change it, then don't make it const in the first place:
void SomeFunction(int* value)
I know I can solve this problem by using const_cast
That's a bad idea - you'll get undefined behaviour if you abuse const_cast and try to modify a constant object. You should use const where you can, but not when you want to modify something.
The const int* means that you have the address of an int that you are not allowed to change.
An int* can be used to change the int it points to. Clearly that violates the above statement that you aren't allowed to change it.
const_cast does not actually "solve the problem". It lets you request to change something which cannot be changed. Such an attempt can cause your program to fail in uncontrolled ways (formally, undefined behavior). In your particular example, the variable a in main is not const, and so const_cast will successfully change it. But that creates close coupling and contradicts the promise made by a function whose signature is const int*.
int* variable = value; is wrong.
It should be,
int variable = *value
and
cout << "Value is " << variable << " end" << endl;
const int * means that the function guarantees that value at this address will not change, but if you can do:
int * variable = value;
Then you can also do
*variable=30;
In doing so, the guarantee of function that is of const pointer will be harmed.