I know that we change const variable value this way in C(by changing it into non-const).
#include<stdio.h>
#include<stdlib.h>
int main()
{
const int var = 10;
int *ptr = &var;
*ptr = 5;
printf("var = %d\n", var);
return 0;
}
similar thing (using a pointer) in C++ gives me a compilation error
How can I update the const variable value in C++?
Modifying a const value through any mechanism (including casting away const-ness) results in "undefined behavior" (UB) which means that you cannot reason about the behavior of the program. The compiler is allowed to assume that const values will never change. Based on that assumption, the compiler might:
Store const values in read-only memory pages; attempting assignment through the pointer would then cause an access violation.
Inline the const value wherever it is used. Because you take a pointer, the compiler will likely also emit some kind of storage for the value (on the stack most likely) so that it has a memory location that can be pointed to, but modifying this value will not cause the inlined values to change.
Something else, possibly including both of the above.
Which one it does can depend on the optimization level selected.
A program that assigns to a const value is effectively "nonsense" and has no meaningful interpretation.
Note that this is UB in both C and C++. You just need to twist the C++ compiler's arm a bit more to get the code to compile (int *ptr = const_cast<int *>(&var);). The C standard permits implicit discarding of a const qualifier in some contexts; the C++ standard is a lot more strict about this.
Most C compilers will emit a warning on int *ptr = &var; regarding discarding of the const qualifier. I would strongly recommend compiling with all warnings enabled and converted to errors (-Wall -Werror on gcc). That would cause the C compiler to also refuse to compile this code.
Note that casting const away from a pointer (or reference) and assigning to the target is not UB when the value was not declared const:
// non-const value
int x = 10;
// take a pointer to x and store it in a pointer-to-const
const int *y = &x;
// cast away the const-ness of the pointer target
int *z = const_cast<int *>(y);
// this is fine; z points at x which is not const
*z = 5;
However, if you find yourself needing const_cast then most likely you are either (1) doing some crazy template metaprogramming, or (2) approaching the problem wrong.
Related
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.
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.
as we all know the usage of const_cast to remove the const-ness of a pointer should be avoided.
But how is it about the other way around?
For my use case I have a function that copies data (bytes) from a non-const source buffer.
I thought a good design decision would be to declare the parameter according to that source buffer fully const.
void copyfunction(const char* const data) { ... }
For a function call like below this would lead to a pointer-type error 'const char* const <-> char*'.
void main() {
char sourcebuffer[] = {0x00};
copyfunction(sourcebuffer);
}
Sure, now I could simply declare the sourcebuffer as const but in my case I don't have access to that variable because it's from a different code location (external library).
void main() {
char sourcebuffer[] = {0x00};
copyfunction(const_cast<const char* const>(sourcebuffer));
}
However the code beyond would work but is it good style (according to my use case)?
I thought declaring the parameter of the copyfunction as const assures the user of not modifying (read-only) the pointer or the location of the source buffer itself.
So in this case the const_cast would only be a necessary evil to enable to function call and not willfully remove the const-ness of a pointer...
Greets
You should not use const_cast to add const, because:
it's unnecessary. T* converts implicitly to const T*. Your question states that char sourcebuffer[] = {0x00}; copyfunction(sourcebuffer); is an error, but that's not true.
it's potentially (albeit unlikely) harmful. It can remove volatile from the pointer type, which is not the intention here and would result in undefined behavior if sourcebuffer were declared as volatile sourcebuffer[].
You should not use const_cast to add const because
In the cases where the operation is safe, it is almost always not required. int* turns into a const int* implicitly.
It can do something you don't want it to do. It can strip volatile, or make you miss the fact that const was added somewhere else in your variables and your const_cast now silently strips them.
In the cases where it is required to add const, its use is dangerous in hard to reason about ways.
There are cases where you need to call const_cast in order to add const that will not happen implicitly.
void assign_ptr( int const*& lhs, int const* rhs ) { lhs = rhs; }
int const foo = 7;
int* bar = nullptr;
assign_ptr( const_cast<int const*&>(bar), &foo );
*bar = 2; // undefined behavior!
std::cout << foo << "#" << &foo << "\n"; // will print probably 7#something
std::cout << *bar << "#" << bar << "\n"; // will print probably 2#same address as above!
the above call to assign_ptr only adds const, but it will not happen implicitly.
A side effect of it is that modification of *bar is undefined behavior, as it modifies a variable declared const (it makes bar, a int*, point at foo a const int).
So while const_cast is required to make the assign_ptr call compile, it is because it was unsafe. The const_cast doesn't make it safer, it just hides the error.
This is a specific case of the rectangle-square problem. Squares are not Rectangles, because if you change the width of a Square its height also changes, and this does not happen when you modify a Rectangle. Similarly, int** are not int const**. (Note that immutable Squares are a kind of immutable Rectangle; it is the mutation that causes the issue. In the case of pointers, a int*const* is a int const*const*: the mutability of the "higher level" pointers causes the problem.)
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’
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Why is my return type meaningless?
Hi, I'm confused about a particular const conversion. I have something like
// Returns a pointer that cannot be modified,
// although the value it points to can be modified.
double* const foo()
{
static double bar = 3.14;
return &bar;
}
int main()
{
double* const x = foo(); // fine
const double* y = foo(); // eh?!
return 0;
}
When I compile this on MSVS 2008 (Express) there is no error, but it seems to me like there should be. The meaning behind x and y are quite different, so it does not seem like there should be this implicit conversion. So is this an issue with the compiler (unlikely), or my understanding of the const-ness involved here (quite likely).
What you did is equivalent to the following:
const int a = 5;
int b = a;
This is (as you probably know) perfectly valid as it creates a copy of the variable. If you do b = 10, a remains 5, so the constness isn't "broken".
As has been asked many other times in many other questions, returning a const value from a function is meaningless. A function returns an rvalue, which by definition cannot be modified. The fact that you can assign it to another variable is no real surprise. Check out these questions & answers for more information:
Should useless type qualifiers on return types be used, for clarity?
Why is my return type meaningless?
where is rvalue stored in c?
The return value cannot be modified. That is, the pointer cannot be modified. However, because at the call site, the return value is an rvalue (without a defined = operator), it cannot be modified anyway.
If the return value was an lvalue (e.g. a reference), this would be possible:
double* &foo()
{
static double bar = 3.14;
double *barP = &bar;
return barP;
}
double myDouble;
foo() = &myDouble;
But this would not be possible:
double* const &foo()
{
static double bar = 3.14;
double *barP = &bar;
return barP;
}
double myDouble;
foo() = &myDouble; // error!
Adding const to the return value (as to quality the pointer as const, not the pointed to data as const) in your case does nothing. If anything, your compiler should warn you about this, because really there's no different if you just remove the const qualifier (barring possible ABI changes, though I'm not sure if the standard allows for ABI changes in this case).
You can always assign an X const, a constant X, to a variable X -- the variable may later be modified, perhaps, but what an X const guarantees is that itself won't be modified, not of course that any copy of it will never be. In your case X is a pointer type, but that does not change this rule.
You can always assign a const X* variable from an X* value: the pointed-to data won't be modified through the pointer variable you have thus assigned (that's what its const means), but of course they may be modified through other pathways.
So in this case you're doing both perfectly legitimate assignments at the same time: there's no reason why the combination of the two legal things should be illegal, in this case, since no expressed constraint is violated anyway.
Use the right-left rule to understand the return type of 'foo'. 'foo' basically returns a (also cross validate through cdecl.org)
const pointer to double
A "const pointer to double" is not the same as "pointer to const double".
In the first case, pointer is const, pointed to value can change.
In the second case, the point can change, the pointed to value cannot change.
Hey jdowner, although these answers here most likely answer your questions, I also highly recommend you read this article regarding const correctness. It goes over all of the possible scenarios and what they mean in plain english.