This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
I know that using const_cast is generally bad idea, but I was playing around with it and I came across a weird behaviour, where:
Two pointers have the same address value, yet when de-referenced, give different data values.
Does anyone have an explanation for this?
Code
#include <iostream>
int main()
{
const int M = 10;
int* MPtr = const_cast<int*>(&M);
(*MPtr)++;
std::cout << "MPtr = " << MPtr << " (*MPtr) = " << (*MPtr) << std::endl;
std::cout << " &M = " << &M << " M = " << M << std::endl;
}
Output
MPtr = 0x7fff9b4b6ce0 (*MPtr) = 11
&M = 0x7fff9b4b6ce0 M = 10
The program has undefined bahaviour because you may not change a const object.
From the C++ Standard
4 Certain other operations are described in this International
Standard as undefined (for example, the effect of attempting to modify
a const object). [ Note: This International Standard imposes no
requirements on the behavior of programs that contain undefined
behavior. —end note ]
So, aside from the "it's undefined behaviour" (which it is), the compiler is perfectly fine to use the fact that M is a constant, thus won't change, in the evaluation of cout ... << M << ..., so can use an instruction that has the immediate value 10, instead of the actual value stored in the memory of M. (Of course, the standard will not say how this works, more than "it's undefined", and compilers are able to choose different solutions in different circumstances, etc, etc, so it's entirely possible that you'll get different results if you modify the code, use a different compiler, different version of compiler or the wind is blowing in a different direction).
Part of the tricky bit with "undefined behaviour" is that it includes things that are "perfectly what you may expect" as well as "nearly what you'd expect". The compiler could also decide to start tetris if it discovers this is what you are doing.
And yes, this is very much one of the reasons why you SHOULD NOT use const_cast. At the very least NOT on things that were originally const - it's OK if you have something along these lines:
int x;
void func(const int* p)
{
...
int *q = const_cast<int *>(p);
*q = 7;
}
...
func(&x);
In this case, x is not actually const, it just becomes const when we pass it to func. Of course, the compiler may still assume that x is not changed in func, and thus you could have problems....
Related
I have a question about how global variables work in c++.
I know global variables are evil so that is not the point of this question. I just want a deeper understanding of what is happening in the following example.
#include <cstdint>
#include <iostream>
#include <vector>
class B
{
public:
B();
~B();
private:
static std::vector<int32_t> v_;
};
B::B()
{
std::cout << "v_.size() = " << v_.size() << std::endl;
for (auto i : v_)
std::cout << i << std::endl;
}
B::~B()
{
std::cout << "v_.size() = " << v_.size() << std::endl;
std::cout << "v_[0] = " << v_[0] << std::endl;
std::cout << "v_.at(0) = " << v_.at(0) << std::endl;
for (auto i : v_)
std::cout << i << std::endl;
}
B b;
std::vector<int32_t> B::v_ { 5, -7 };
int main()
{
return 0;
}
Gives this output:
$ ./test
v_.size() = 0
v_.size() = 2
v_[0] = 0
v_.at(0) = 0
0
0
Why is the size of the vector in the destructor of B still 2?
When I access the elements of the vector I get random memory, which I sort of understand because the vector gets cleaned up before B. But to me the size of the vector should be 0 or even way better throw some sort of error when asking for the size. Even when using at() function It doesn't throw an error because the size is still 2.
I also know I can fix this by switching the initialization of b and the vector. My question is more why this specific example doesn't throw some sort of error, cause in my opinion it should.
Note: like my comment: why does this behavior fall under undefined behavior instead of reading or writing an illegal memory location since the vector doesn't exist at that point? I was kinda thinking this would/should generate a seg fault and I don't understand why it doesn't
Undefined behavior means that the behavior of your program is not defined by the C++ standard. A conforming C++ compiler can do anything with a program that has, or will, exhibit undefined behavior (yes, UB can time travel).
Your program exhibits undefined behavior by accessing v_ as an object prior to it being constructed in B::B. Given that it does this, nothing about your programs execution is specified or constrained by the C++ standard.
In this case, the compiler treats the UB access as if it was accessing an empty std::vector. This is valid, because anything is valid. The program then proceeds as-if you hadn't done the UB (other than the above symptom), which is also a valid option.
If we imagine removing the UB in the ctor, during destruction your program again exhibits UB. This time by accessing v_ as a vector object after it was destroyed. Again, by doing this the behavior of your program is not defined or constrained by the C++ standard, before, at, and after the UB.
In this case, it behaves as if you have a vector of 2 values whose values are 0. That is conforming, because anything is conforming.
One of many possibilities is that the data was recycled on the heap, but the pointers where left dangling. Treating the vector's "rotted" data as pointers they still point 2 sizeof(int) apart, and .size() reads that as 2. The data pointed to, however, has been recycled on the heap, and there is different data there.
So, as of now, it seems to be impossible to actually modify a "const" value in C++ (tested in VS 2017).
const int a = 5;
int* ptr = (int*)&a; // Method 1
*((int*)(&a)) = 6; // Method 2
int* ptr = const_cast<int*>(&a); // Method 3
*ptr = 55;
cout << a << "\t" << &a << endl;
cout << *ptr << "\t" << ptr << endl;
Result:
5 SOMEMEMORYADDRESS
55 SOMEMEMORYADDRESS
Anyone got any idea what else can be tried to achieve the effect? Really curious how it is possible to have 1 memory address (at least according to the console) with 2 values.
Please note: there are topics like this for older C++ versions (and they used to work in the past - but they don't, anymore).
Really curious how it is possible to have 1 memory address (at least according to the console) with 2 values.
It's because you invoked undefined behavior. The C++ standard, from C++98, has expressly forbidden you from modifying an object that is declared const. And the standard has a catch-all statement such that if you do anything which causes modification of a const object, you get undefined behavior.
Because modifying an object declared const is UB, the compiler is free to assume that this object will never be modified. So, since the compiler can see that a is const and it is initialed to 5, it is 100% valid for the compiler to at compile time replace everything which revers to this object with 5. So when you do cout << a, the compiler is free to not bother to access memory; it can just do cout << 5.
If you did something to modify the memory behind a, that's UB, so the compiler doesn't have to care about what happens in that case.
they used to work in the past - but they don't, anymore
No, they never "worked". They merely just so happened to do what you thought they should. But C++ never guaranteed that compilers would behave in this way, so you have no right to complain about compilers changing that behavior now.
This question already has answers here:
Vector going out of bounds without giving error
(4 answers)
Closed 7 years ago.
Numerous questions/answers inform me that std::vector<T>::resize(n) will increase capacity and size, whilst std::vector<T>::reserve(n) only increases capacity.
One example is Choice between vector::resize() and vector::reserve().
A comment in that question indicates that after use of reserve(n), the use of
vec[i less than n] = ..
is undefined behaviour, and many examples given are claimed to lead to segfaults.
When I compile and run
#include <vector>
#include <iostream>
void f(const std::vector<double> &s) {
std::cout << "s.size() = " << s.size() << std::endl;
std::cout << "s.capacity() = " << s.capacity() << std::endl;
}
int main() {
std::size_t n = 20121;
std::vector<double> a;
a.reserve(2*n);
a[n] = 2.5;
std::cout << "a["<<n<<"] = " << a[n] << std::endl;
f(a);
std::vector<double> b;
b.resize(2*n);
b[n] = 2.5;
std::cout << "b["<<n<<"] = " << b[n] << std::endl;
f(b);
}
my output is
a[20121] = 2.5
s.size() = 0
s.capacity() = 40242
b[20121] = 2.5
s.size() = 40242
s.capacity() = 40242
Questions:
Has there been a change that makes this ok? Is this just my compiler (g++ v5.2.0) giving me undefined, but nice, behaviour?
As a second point of curiosity, why does f(a) tell me the size is 0 (guessed answer: no push_back calls), even though a[n] returns a valid value?
By definition "Undefined Behavior" means that the result that you see on the execution of that line is not defined and can/will change with different runs.
Is this just my compiler (g++ v5.2.0) giving me undefined, but nice,
behaviour?
The nice behavior can be a mix of how std::vector is implemented in the version you are compiling and the state of memory when your program was executed. The compiler has almost no role to play in showing a "nice behavior".
One line answer: What you are noticing is indeed undefined behavior. The runtime is free to give any output/behavior including shooting monkeys out of your monitor, on hitting an UB.
As always with undefined behavior, your compiler may produce what you might think would be a "reasonable/nice" behavior, but the fact that you're seeing "nice" behavior doesn't mean that what you're doing is okay! This behavior may change at any time, with any new version of the compiler, when you compile and/or run it on any other machine or OS, or when you re-run your program during a different lunar phase.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Modifying a const through a non-const pointer
I'm studying C++, and very interesting about pointers. And I tried to change value of a constant value (my teacher called it backdoor, please clarify if I'm wrong) like this:
const int i = 0;
const int* pi = &i;
int hackingAddress = (int)pi;
int *hackingPointer = (int*)pi;
*hackingPointer = 1;
cout << "Address:\t" << &i << "\t" << hackingPointer << endl;
cout << "Value: \t" << i << "\t\t" << *hackingPointer << endl;
system("PAUSE");
return 0;
However, the result is very strange. Although the two addresses are the same, the values are different.
How is my code executed? And where is 0 and 1 value is stored exactly?
You've discovered a little thing that C++ developers call undefined behavior. You told the compiler that "i is a constant with the value 0". So when you ask the compiler for the value of i, it tells you that it is 0.
Mucking around with trying to change the value of a constant violates the assumptions made by the compiler (that constants are going to be, well, constant), and so, the compiler is going to generate invalid or inconsistent code.
There are a lot of situations in C++ where it is possible to do something without the compiler catching it as an error, but the result is undefined. And if you do that, then you get results like what you're seeing. The compiler does something weird and unexpected.
Oh, and if your teacher is trying to teach you anything from an example such as this, he's wrong, and you should be very scared.
The only guarantee you get from code like this is this:
the compiler can do literally anything it likes
When you write code, you have an implicit contract with the compiler:
"If I write well-defined C++ code, then you convert it into an executable with the same effects as described by the C++ standard".
When you do something like this, you violate the contract. And then the compiler isn't obliged to follow it either. If you give the compiler code that is not well-defined according to the C++ standard, then it can't, and isn't going to, create an executable which does as the C++ standard specifies.
It seems, that compiler has optimized (inlined int const value)
cout << "Value: \t" << i << "\t\t" << *hackingPointer << endl;
to
cout << "Value: \t" << 0 << "\t\t" << *(0x0044ff28) << endl;
Anyway, you have still succeeded to change value of memory where i is stored. But do not try this at home :-)
It is not permitted to change the values of a constant, in fact it's undefined behaviour so your program could do anything as a result.
In this instance it looks like your compiler optimised the read away at compile time because it knew the value is fixed. Lots of implementations might just crash when you try and change it, but you cannot and should not bet or rely upon the result of any undefined behaviour ever.
Check this example for const_cast of int.
I am using VC++ 2008 to compile this.
#include <iostream>
using namespace std;
void main() {
const int x=0;
int y=90;
int *p = const_cast<int *> (&x);
*p=y;
cout<<" value of x: "<<x<<" addr of x "<<&x<<endl
<<" and *p : "<<*p<<" and addr p "<<p<<endl;
}
================
The output is
value of x: 0 addr of x 0012FF60
and *p : 90 and addr p 0012FF60
You should not const_cast a variable defined as const. I don't have the standard at hand but I'm fairly certain it defines such an operation as resulting in undefined behaviour.
For an example of why this results in undefined behaviour consider an MCU where things defined as const are stored in non-volatile memory (flash, EEPROM or something even less volatile).
There's more to read in the C++ FAQ Lite.
For the following program
#include <iostream>
int main() {
const int x=0;
int y=90;
int *p = const_cast<int *> (&x);
*p=y;
std::cout << " value of x: " << x << " addr of x " << &x << '\n'
<< " and *p : " << *p << " and addr p " << p << '\n';
return 0;
}
VC9 prints the same address for me. However:
You are invoking undefined behavior, because you are not allowed to cast away const from an object if that object was a real const value. (OTOH, you are, for example, allowed to cast away const from a const reference if that reference refers to a non-const value.)
In theory, when you invoke undefined behavior, according to the C++ standard your program might work as you expect, or it might not, or it might do so only on Sundays, or unless it's a holiday and full moon. But it might just as well format your HD, blow up your monitor, and make your girlfriend pregnant. According to the C++ standard, all this (and an infinite amount of other possibilities), are Ok.
In practice, such a program might print out funny addresses.
The compiler might completely optimize away all your code and just put in dummy values for printing. It shouldn't, however, do so for Debug builds. (Although that's a QoI issue, not a requirement.)
The compiler is optimizing away the aliasing. Try it in debug mode, with optimizations disabled.
edit
The compiler is optimizing away the aliasing, yes, but it's not an error in the optimization. Rather, the code is doing something undefined, which is leading to an unwanted but legal behavior. Staffan's answer clarifies this.
As the FAQ said, in almost all cases where you're tempted to use const_cast, you should be using mutable instead. If, as in the sample code here, you can't use mutable, this is an indication that something might be wrong.
maybe it was optimized by the compiler. he have all rights to do this.
it is drawback of misusing const_cast.
never use const_cast in such way.