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.
Related
I'm curious about why my research result is strange
#include <iostream>
int test()
{
return 0;
}
int main()
{
/*include either the next line or the one after*/
const int a = test(); //the result is 1:1
const int a = 0; //the result is 0:1
int* ra = (int*)((void*)&a);
*ra = 1;
std::cout << a << ":" << *ra << std::endl;
return 0;
}
why the constant var initialize while runtime can completely change, but initialize while compile will only changes pointer's var?
The function isn't really that relevant here. In principle you could get same output (0:1) for this code:
int main() {
const int a = 0;
int* ra = (int*)((void*)&a);
*ra = 1;
std::cout << a << ":" << *ra;
}
a is a const int not an int. You can do all sorts of senseless c-casts, but modifiying a const object invokes undefined behavior.
By the way in the above example even for std::cout << a << ":" << a; the compiler would be allowed to emit code that prints 1:0 (or 42:3.1415927). When your code has undefinded behavior anything can happen.
PS: the function and the different outcomes is relevant if you want to study internals of your compiler and what it does to code that is not valid c++ code. For that you best look at the output of the compiler and how it differs in the two cases (https://godbolt.org/).
It is undefined behavior to cast a const variable and change it's value. If you try, anything can happen.
Anyway, what seems to happen, is that the compiler sees const int a = 0;, and, depending on optimization, puts it on the stack, but replaces all usages with 0 (since a will not change!). For *ra = 1;, the value stored in memory actually changes (the stack is read-write), and outputs that value.
For const int a = test();, dependent on optimization, the program actually calls the function test() and puts the value on the stack, where it is modified by *ra = 1, which also changes a.
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.
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
When I tried below code I got strange results.I am trying to change value of constant by using the pointers.But when I output the results pointer value and the original variable variable value its giving two different values.Can anyone explain what exactly happens when explicit conversion take place?
int main()
{
int *p ;
const int a = 20;
p=(int *)&a;
*p = *p +10;
cout<<"p is"<<*p<<"\na is"<<a;
}
output:
p is 30
a is 20
Both C and C++ say that any attempt to modify an object declared with the const qualifier results in undefined behavior.
So as a is object is const qualified, the *p = *p +10; statement invokes undefined behavior.
First of - You really shouldn't be doing this. const is a constant, meaning don't change it! :)
Now to explain what happens (I think):
The space on the stack is allocated for both variables, p and a. This is done for a because it has been referenced by an address. If you removed p, you'd effectively remove a as well.
The number 20 is indeed written to the a variable, and modified to 30 via p, which is what is being printed.
The 20 printed is calculated at compile time. Since it is a const, the compiler optimized it away and replaced with 20, as if you did a #define a 20.
Don't Do That.
If you would write this code in C++ with an explicit cast, you would get something like this:
int main()
{
int *p ;
const int a = 20;
p= const_cast<int*>(&a); // the change
*p = *p +10;
cout<<"p is"<<*p<<"\na is"<<a;
}
Now, this code tells a bit more about what's going on: the constant is cast to a non-constant.
If you are writing a compiler, constants are special variables that are allowed to be 'folded' in the const folding phase. Basically this means that the compiler is allowed to change your code into this:
int main()
{
int *p ;
const int a = 20;
p= const_cast<int*>(&a);
*p = *p +10;
cout<<"p is"<<*p<<"\na is" << 20; // const fold
}
Because you're also using &a, you tell the compiler to put the value 20 in a memory location. Combined with the above, you get the exact results you describe.
This is undefined behavior.
A compiler can assume that nothing is going to change the value of a const object. The compiler knows that the value of "a" is 20. You told the compiler that. So, the compiler actually goes ahead and simply compiles the equivalent of
cout << "p is" << *p << "\na is" << 20;
Your compiler should've also given you a big fat warning, about "casting away const-ness", or something along the same lines, when it tried to compile your code.
Although it is defined as undefined behaviour (as everyone else tells you), it could be that your compiler has allocated a storage location (int) for the const int; that is why the *p= *p + 10 works, but may have repaced a in the output statement with the value 20, as it is supposed to be constant.
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.