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.
Related
So I have a following snippet (and a good reason behind it):
#include <iostream>
volatile const float A = 10;
int main() {
volatile const float* ptr = &A;
float* safePtr = const_cast<float*>(ptr);
*safePtr = 20;
std::cout << A << std::endl;
return 0;
}
Under G++ v8.2.0 (from MinGW suite), this program compiles fine and outputs 20 as expected. Under VS2019, it compiles, but throws a runtime exception - Exception thrown at 0x00007FF7AB961478 in Sandbox.exe: 0xC0000005: Access violation writing location 0x00007FF7AB969C58.
Is there a way to make VS2019 behave the same way the G++ does? And how to do it with CMake?
All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.
As governed by [dcl.type.cv]/4, your program has undefined behaviour
Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior. [ Example:
// ...
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
and as such, demons may fly out of your nose and any kind of analysis of your program beyond this point, including comparison of the behaviour for different compilers, will be a fruitless exercise.
You question is interesting, it would seem that const_cast would allow to change an underlying const object, that would be nice indeed, but unfortunately no, const objects cannot be safely changed by any means, even though it appears to be working.
const_cast makes it possible to form a reference or pointer to non-const type that is actually referring to a const object or a reference or pointer to non-volatile type that is actually referring to a volatile object. Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.
You should not try to make this work by ignoring the problem, my guess is that you are running the program in VS in debug mode so it catches the error where g++ doesn't, but if you run your program through the debugger you'll likely see the same problem, though it's not guaranteed as per the nature of undefined behavior.
The way to go is to fix the code, not to ignore the problem.
As point out, you cannot legally modify const objects...
But you can have const reference on non-const object:
so you might use the following:
const float& A = *([]() { static float a = 10; return &a; }());
// const float& A = []() -> float& { static float a = 10; return a; }();
int main() {
float* safePtr = const_cast<float*>(&A);
*safePtr = 20;
std::cout << A << std::endl;
}
(No need of volatile neither).
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.
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.
I need to clear a basic concept. This code works fine. Can somebody explain me that if the function calDouble already returning the address (reference) of int why I need to use & operator further in main int *j = &calDouble(i); to get the address (reference) of int? Thanks.
int& calDouble(int x)
{
x = x*2;
return x;
}
int main(int argc, char *argv[])
{
int i = 99;
int *j = &calDouble(i);
system("PAUSE");
return EXIT_SUCCESS;
}
int& calDouble(int x) doesn't return an address, but a reference to an int.
You need to take the address of the reference to be able to assign it to a pointer.
Note however that your code invokes undefined behavior. Because you pass the parameter by value, a copy of it is created inside the function. So you return a local variable by reference, which is not legal.
I think your confusion comes from &. This can be used in two ways:
applied to a variable &x, it takes its address
when in a declaration int& x, it defines a reference
A reference is just an alias, a different name for a variable.
int x = 0;
int& y = x;
Now, x and y refer to the same variable.
int* z = &x;
takes the address of x.
int& is a reference type. It is not the address.
To see what &calDouble(i) does, consider if we had broken it into two statements:
int& x = calDouble(i);
... = &x;
The calDouble() function returns a reference type, and the prepended & then takes the address-of whatever was returned. So the type is now int*, which is why that line compiles.
However, your program exhibits undefined behavior! The x in calDouble() goes away once the function ends. The value that was originally there may still be in memory, which is why your program "works". But this is not reliable in production code, and one day your perfectly working test program may blow-up the moment it's deployed.
It's generally a bad idea to return a reference to a local variable for this vary reason. (You'll see class methods return references to member data, which is fine as long as the object is still in scope since those variables will still exist.) Just return a regular int and get on with life. An optimizing compiler can do some return value optimization if you're really worried about performance when returning large objects.
The following code compile well both with GCC (4.2-4.6) and with Clang (2.1), but when I run the executable it gives me "Bus error: 10". I don't understand the reason.
#include <iostream>
struct A
{
static int const v;
A() { ++*const_cast<int *>(&A::v); }
};
int const A::v = 0;
int main(int argc, char * argv[])
{
A a, b, c;
std::cout << a.v << std::endl;
return 0;
}
I think the relevant quote is:
§ 7.1.6.1 (4) from N3242:
Except that any class member declared mutable can be modified, any
attempt to modify a const object during its lifetime results in
undefined behavior.
The examples illustrate the point using const_cast. As James pointed out: the quote can be found in §7.1.5 in the C++03 standard.
A little elaboration: That language rule allows the compiler to use read-only memory (if it is available on the target architecture) when something is declared const. Without this rule const-ness could always be casted away without fearing any consequences and using it would only be a matter of developer discipline. The way it is you can at least tell people that they are invoking UB, which usually is a good deterrent. The const_cast itself is of minor relevance as it does not matter how you trick the compiler in letting you manipulate a const object.
5.2.11.7:
Depending on the type of the object, a write operation through the
pointer, lvalue or pointer to data member resulting from a const_cast
that casts away a const-qualifier) may produce undefined behavior
(7.1.5.1)
In your case, you are trying to modify data that is in read-only segment.
Because you're not allowed to modify variables declared as const.
Just because you've cast away const, doesn't mean that you will succeed in writing to that memory.
All that const_cast<T> does is remove the const-ness of the variable from the compiler's perspective. That lets the compiler go ahead and emit code to write to the variable. But at runtime, if the compiler/linker happened to put the variable in read-only memory, then the hardware will stop you writing there no matter how you cast it.
I don't have a solution for the actual problem. I just can say, don't use const_cast unless the intention is to call a const member function from a non-const member function and "const_cast" the const result (to make it a mutable result for the non-const member function).
But I have a proposal for improving your design:
class A
{
private:
static int v;
public:
A() { ++v; }
static int get_v() { return v; }
};
int A::v = 0;
int main(int argc, char * argv[])
{
A a, b, c;
std::cout << a.get_v() << std::endl;
return 0;
}
Basically, if a variable is declared const, the compiler is allowed to emit the results to read only memory. Taking a pointer/reference to a const object and then using const_cast to remove the const can result in undefined behavior.
In general, it is only safe to use const_cast if the object being refered to is non-const (even if the pointer/reference you have is const).
The problem is this line :
static int const v;
Because you declared it const, the const_cast is causing an undefined behaviour - in your case you are lucky with getting bus error (it is a segmentation fault on my system).
Declare it non-const, and you can call const_cast on it without problems.