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).
Related
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.
In my work the use of const_cast is under some circumstances unavoidable.
Now I have to const_cast some pretty complicated types and actually I don't want to write all this type clutter in the const_cast<Clutter> expressions, especially if Clutter is very long.
My first idea was to write const_cast<>(myType), but my compiler cannot deduce the non-const type of myType. So I thought about helping my compiler and I deviced the following approach, which compiles.
#include <stdlib.h>
#include <iostream>
int main(int, char**) {
const int constVar = 6;
using T = typename std::remove_cv<decltype(constVar)>::type;
auto& var = const_cast<T&>(constVar);
var *= 2;
std::cout << &constVar << " " << &var << "\n"; // Same address!
std::cout << constVar << " " << var << "\n";
return EXIT_SUCCESS;
}
Unfortunately, the program gives me the output 6 12 instead of the expected 6 6, which I really didn't understand?
What is wrong with my approach?
From the documentation of const_cast:
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.
So what you have is undefined behavior.
Also of interest is this note from cv type qualifiers.
const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.
If you have
void foo(const int& a)
{
const_cast<int&>(a) = 4;
}
then
int a = 1;
foo(a);
is perfectly legal, but
const int a = 1;
foo(a);
invokes an undefined behaviour, because in foo, a was originally const.
This is useful in some case (usually when interfacing old C library), but in most cases, you are doing something wrong and should rethink your solution.
And to answer why const_cast<> isn't a thing, I'd say for two reasons. First, when you do const_cast you should really know what you are doing, if some kind of template deduction was allowed, it would make doing unintended mistakes more likely to occur. And secondly const_cast can also be used to remove volatile and how can compiler know what you want to cast away?
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.
In a response to my comment to some answer in another question somebody suggests that something like
void C::f() const
{
const_cast<C *>( this )->m_x = 1;
}
invokes undefined behaviour since a const object is modified. Is this true? If it isn't, please quote the C++ standard (please mention which standard you quote from) which permits this.
For what it's worth, I've always used this approach to avoid making a member variable mutable if just one or two methods need to write to it (since using mutable makes it writeable to all methods).
It is undefined behavior to (attempt to) modify a const object (7.1.6.1/4 in C++11).
So the important question is, what is a const object, and is m_x one? If it is, then you have UB. If it is not, then there's nothing here to indicate that it would be UB -- of course it might be UB for some other reason not indicated here (for example, a data race).
If the function f is called on a const instance of the class C, then m_x is a const object, and hence behavior is undefined (7.1.6.1/5):
const C c;
c.f(); // UB
If the function f is called on a non-const instance of the class C, then m_x is not a const object, and hence behavior is defined as far as we know:
C c;
const C *ptr = &c;
c->f(); // OK
So, if you write this function then you are at the mercy of your user not to create a const instance of C and call the function on it. Perhaps instances of C are created only by some factory, in which case you would be able to prevent that.
If you want a data member to be modifiable even if the complete object is const, then you should mark it mutable. That's what mutable is for, and it gives you defined behavior even if f is called on a const instance of C.
As of C++11, const member functions and operations on mutable data members should be thread-safe. Otherwise you violate guarantees provided by standard library, when your type is used with standard library functions and containers.
So in C++11 you would need to either make m_x an atomic type, or else synchronize the modification some other way, or as a last resort document that even though it is marked const, the function f is not thread-safe. If you don't do any of those things, then again you create an opportunity for a user to write code that they reasonably believe ought to work but that actually has UB.
There are two rules:
You cannot modify a const object.
You cannot modify an object through a const pointer or reference.
You break neither rule if the underlying object is not const. There is a common misunderstanding that the presence of a const pointer or const reference to an object somehow stops that object from changing or being changed. That is simply a misunderstanding. For example:
#include <iostream>
using namespace std;
// 'const' means *you* can't change the value through that reference
// It does not mean the value cannot change
void f(const int& x, int* y)
{
cout << "x = " << x << endl;
*y = 5;
cout << "x = " << x << endl;
}
int main()
{
int x = 10;
f(x, &x);
}
Notice no casts, nothing funny. Yet an object that a function has a const reference to is modified by that function. That is allowed. Your code is the same, it just does it by casting away constness.
However, if the underlying object is const, this is illegal. For example, this code segfaults on my machine:
#include <iostream>
using namespace std;
const int i = 5;
void cast(const int *j)
{
*const_cast<int *>(j) = 1;
}
int main(void)
{
cout << "i = " << i << endl;
cast(&i);
cout << "i = " << i << endl;
}
See section 3.4.3 (CV qualifiers) and 5.2.7 (casting away constness).
Without searching any further, § 1.9/4 in the C++11 Standard reads:
Certain other operations are described in this International Standard
as undefined (for example, the effect of attempting to modify a const
object).
And this is what you are trying to do here. It does not matter that you are casting away constness (if you didn't do it, the behaviour is well defined: your code would fail to compile). You are attempting to modify a const object, so you are running into undefined behaviour.
Your code will appear to work in many cases. But it won't if the object you are calling it on is really const and the runtime decided to store it in read-only memory. Casting away constness is dangerous unless you are really sure that this object was not const originally.
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.