changing the value of const variable in C++ [duplicate] - c++

This question already has answers here:
Weird Behaviour with const_cast [duplicate]
(2 answers)
Closed 6 years ago.
I am trying to change the value of a variable which is defined as int const as below.
const int w = 10;
int* wp = const_cast <int*> (&w);
*wp = 20;
The value of w didn't change and was 10 even after the assignment, though it shows as if both w and wp are pointing to the same memory location. But I am able to the change the value of w, if defined as below while declaring
int i = 10;
const int w = i;
If I change the declaration of i to make it const like in
const int i = 10;
The value of w doesn't change.
In the first case, how come the value of w didn't change, even though w and wp point to the same memory location [ that was my impression I get when I print their addresses ]
What difference it's to the compiler that it treats both the cases differently?
Is there a way to make sure that w doesn't lose constness, irrespective of the way it is defined?

This is one of the cases where a const cast is undefined, since the code was probably optimized such that w isn't really a variable and does not really exist in the compiled code.
Try the following:
const volatile int w = 10;
int &wr = const_cast <int &> (w);
wr = 20;
std::cout << w << std::endl;
Anyhow, I would not advise abusing const_cast like that.

The code in the above example translates into the following assembler:
movl $10, 28(%esp) //const int i = 10;
leal 28(%esp), %eax //int* wp = const_cast <int*>(&i);
movl %eax, 24(%esp) //store the pointer on the stack
movl 24(%esp), %eax //place the value of wp in eax
movl $20, (%eax) //*wp = 20; - so all good until here
movl $10, 4(%esp) //place constant value 10 onto the the stack for use in printf
movl $.LC0, (%esp) // load string
call printf //call printf
Because the original int i was declared constant, the compiler reserves the right to use the literal value instead of the value stored on the stack. This means that the value does not get changed and you are stuck with the original 10.
The moral of the story is compile time constants should remain constant because that is what you are telling the compiler. The moral of the story is that casting away constness in order to change a constant can lead to bad things.

const_cast doesn't take away the const-ness of a variable as defined. If you were to pass a non-const variable by reference in to a method taking a const reference like void foo(const int& x) then you could use const_cast to modify the value of x within foo, but only if the variable you actually passed in was not const in the first place.

Why can't you just re-bind the constant? So instead of
const int w = 10;
int* wp = const_cast <int*> (&w);
*wp = 20;
// some code
just introduce the different constant with the same name
const int w = 10;
{
const int w = 20;
// the same code
}
If the "new" constant should depend on its own value, you should introduce another constant (const int _w = w; const int w = _w * 2;). The unnecessary assignments will be optimized out by compiler--because we've seen it has done such optimisation, as it's the reason why you asked your question.

You should not being changing the const value. There is a reason it is const and trying to change it will most likely just result in errors. If the const is stored in a read only memory section then you will get access violations.

Good question. I think the confusion comes from the fact that C++ uses the keyword ‘const’ for two different concepts depending on the context. These concepts are constant and read-only variables.
When a value of a ‘const’ variable can be calculated during the compilation, it creates a true constant. References to such constant are replaced with its value whenever it is used. That’s why there is no location in the memory that can be changed to affect all places where it is used. It is like using #define.
When value of a ‘const’ variable cannot be calculated during the compilation, it creates a read-only variable. It has a location in the memory that contains a value but compiler enforces a read-only behavior.

Here's a refresher, it should be noted that this is in C. This is a deceptively tricky underpinnings of the usage of a variable or pointer using the const keyword. This highlights the difference between the pointer variable foo and how the meaning of it can change by using the said keyword.
char const *foo;
char * const foo;
const char *foo;
The first and last declarations, makes the data pointed to by ‘foo’ read-only, but, you can change the address pointed to by ‘foo’ e.g.
const *char foo; /* OR char const *foo */
char str[] = "Hello";
foo = &str[0]; /* OK! */
foo[1] = 'h'; /* BZZZZTTT! Compile Fails! */
The middle declaration in the above, makes the pointer read-only, i.e. you cannot change the address of the data pointed to by ‘foo’
char * const foo;
char str[] = "Hello";
foo = &str[0]; /* BZZZZTTT! Compile Fails! */

My guess would be that declaring w const allows the compiler to perform more aggressive optimizations such as inlining w's value and reordering instructions. Wether w appears to change or not depends on which optimizations were applied in the precise case and is not under your control.
You can't force w to be totally const. The cons_cast should be a hint to the programmer that they might be doing something fishy.

Related

const vs non-const variable with no change in value once assign

In C++, if value of a variable never gets changed once assigned in whole program VS If making that variable as const , In which case executable code is faster?
How compiler optimize executable code in case 1?
A clever compiler can understand that the value of a variable is never changed, thus optimizing the related code, even without the explicit const keyword by the programmer.
As for your second, question, when you mark a variable as const, then the follow might happen: the "compiler can optimize away this const by not providing storage to this variable rather add it in symbol table. So, subsequent read just need indirection into the symbol table rather than instructions to fetch value from memory". Read more in What kind of optimization does const offer in C/C++? (if any).
I said might, because const does not mean that this is a constant expression for sure, which can be done by using constexpr instead, as I explain bellow.
In general, you should think about safer code, rather than faster code when it comes to using the const keyword. So unless, you do it for safer and more readable code, then you are likely a victim of premature optimization.
Bonus:
C++ offers the constexpr keyword, which allows the programmer to mark a variable as what the Standard calls constant expressions. A constant expression is more than merely constant.
Read more in Difference between `constexpr` and `const` and When should you use constexpr capability in C++11?
PS: Constness prevents moving, so using const too liberally may turn your code to execute slower.
In which case executable code is faster?
The code is faster in case on using const, because compiler has more room for optimization. Consider this snippet:
int c = 5;
[...]
int x = c + 5;
If c is constant, it will simply assign 10 to x. If c is not a constant, it depend on compiler if it will be able to deduct from the code that c is de-facto constant.
How compiler optimize executable code in case 1?
Compiler has harder time to optimize the code in case the variable is not constant. The broader the scope of the variable, the harder for the compiler to make sure the variable is not changing.
For simple cases, like a local variables, the compiler with basic optimizations will be able to deduct that the variable is a constant. So it will treat it like a constant.
if (...) {
int c = 5;
[...]
int x = c + 5;
}
For broader scopes, like global variables, external variables etc., if the compiler is not able to analyze the whole scope, it will treat it like a normal variable, i.e. allocate some space, generate load and store operations etc.
file1.c
int c = 5;
file2.c
extern int c;
[...]
int x = c + 5;
There are more aggressive optimization options, like link time optimizations, which might help in such cases. But still, performance-wise, the const keyword helps, especially for variables with wide scopes.
EDIT:
Simple example
File const.C:
const int c = 5;
volatile int x;
int main(int argc, char **argv)
{
x = c + 5;
}
Compilation:
$ g++ const.C -O3 -g
Disassembly:
5 {
6 x = c + 5;
0x00000000004003e0 <+0>: movl $0xa,0x200c4a(%rip) # 0x601034 <x>
7 }
So we just move 10 (0xa) to x.
File nonconst.C:
int c = 5;
volatile int x;
int main(int argc, char **argv)
{
x = c + 5;
}
Compilation:
$ g++ nonconst.C -O3 -g
Disassembly:
5 {
6 x = c + 5;
0x00000000004003e0 <+0>: mov 0x200c4a(%rip),%eax # 0x601030 <c>
0x00000000004003e6 <+6>: add $0x5,%eax
0x00000000004003e9 <+9>: mov %eax,0x200c49(%rip) # 0x601038 <x>
7 }
We load c, add 5 and store to x.
So as you can see even with quite aggressive optimization (-O3) and the shortest program you can write, the effect of const is quite obvious.
g++ version 5.4.1

How does C++ keep the const value? [duplicate]

This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
#include <iostream>
using namespace std;
int main() {
const int a = 10;
auto *b = const_cast<int *>(&a);
*b = 20;
cout << a << " " << *b;
cout << endl << &a << " " << b;
}
The output looks like:
10 20
0x7ffeeb1d396c 0x7ffeeb1d396c
The a and *b are at the same address, why do they have different value?
Most probably this is caused by optimization.
As molbdnilo already said in his comment: "Compilers trust you blindly. If you lie to them, strange things can happen."
So when optimization is enabled, the compiler finds the declaration
const int a = 10;
and thinks "ah, this will never change, so we don't need a "real" variable and can replace all appearances of a in the code simply with 10". This behavior is called constant folding.
Now in the next line you "cheat" the compiler:
auto *b = const_cast<int *>(&a);
*b = 20;
and change a, although you have promised not to do so.
The result is confusion.
Like a lot of people have already mentioned and Christian Hackl has thoroughly analyzed in his excellent in-depth answer, it's undefined behavior. The compiler is generally allowed to apply constant folding on constants, which are explicitly declared const.
Your question is a very good example (I don't know how anyone can vote it down!) why const_cast is very dangerous (and even more when combined with raw pointers), should be only used if absolutely necessary, and should be at least thoroughly commented why it was used if it was unavoidable. Comments are important in that case because it's not only the compiler you are "cheating":
Also your co-workers will rely on the information const and rely on the information that it won't change. If it DOES change though, and you didn't inform them, and did not comment, and did not exactly know what you were doing, you'll have a bad day at work :)
Try it out: Perhaps your program will even behave different in debug build (not optimized) and release build (optimized), and those bugs are usually pretty annoying to fix.
I think it helps to view const like this:
If you declare something as const it is actually not the compiler that ensures that you dont change it, but rather the opposite: you make a promise to the compiler that you wont change it.
The language helps you a bit to keep your promise, eg you cannot do:
const int a = 5;
a = 6; // error
but as you discovered, you indeed can attempt to modify something that you declared const. However, then you broke your promise and as always in c++, once you break the rules you are on your own (aka undefined behaviour).
The a and *b are at the same address, why do they have different
value?
They don't, not according to C++. Neither do they, according to C++.
How can that be? The answer is that the C++ language does not define the behaviour of your program because you modify a const object. That's not allowed, and there are no rules for what will happen in such a case.
You are only allowed to use const_cast in order to modify something which wasn't const in the first place:
int a = 123;
int const* ptr1 = &a;
// *ptr1 = 456; // compilation error
int* ptr2 = const_cast<int*>(ptr1);
*ptr2 = 456; // OK
So you've ended up with a program whose behaviour is not defined by C++. The behaviour is instead defined by compiler writers, compiler settings and pure chance.
That's also what's wrong with your question. It's impossible to give you a correct answer without knowing exactly how you compiled this and on which system it runs, and perhaps even then there are random factors involved.
You can inspect your binary to find out what the compiler thought it was doing; there are even online tools like https://gcc.godbolt.org/ for that. But try to use printf instead of std::cout for such an analysis; it will produce easier-to-read assembly code. You may also use easier-to-spot numbers, like 123 and 456.
For example, assuming that you even use GCC, compare these two programs; the only difference is the const modifier for a:
#include <stdio.h>
int main() {
int const a = 123;
auto *b = const_cast<int *>(&a);
*b = 456;
printf("%d", a);
printf("%d", *b);
}
#include <stdio.h>
int main() {
int a = 123;
auto *b = const_cast<int *>(&a);
*b = 456;
printf("%d", a);
printf("%d", *b);
}
Look at what the printf("%d", a); call becomes. In the const version, it becomes:
mov esi, 123
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
In the non-const version:
mov eax, DWORD PTR [rbp-12]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
Without going too much into the details of assembly code, one can see that the compiler optimised the const variable such that the value 123 is pushed directly to printf. It doesn't really treat a as a variable for the printf call, but it does do so for the pointer initialisation.
Such chaos is the nature of undefined behaviour. The moral of the story is that you should always avoid undefined behaviour, and thinking twice before casting is an important part of allowing the compiler to help you in that endeavor.
Compiling your code once with const and once without const using gcc, shows that there either no space is allocated for a, or it's content is being ignored in const version. (even with 0 optimization) The only difference in their assembly result is the line which you print the a. Compiler simply prints 10 instead of refering to memory and fetching contents of a: (left side is const int a and right side is int a version)
movl $10, %esi | movl -36(%rbp), %eax
> movl %eax, %esi
As you can see there is an extra memory access for non-const version, which we know is expensive in terms of time. So the compiler decided to trust your code, and concluded that a const is never to be changed, and replaced its value wherever the variable is referenced.
Compiler options: --std=c++11 -O0 -S

Suppose I declare an int but don't initialize it; what value is it? Can someone clear this up for me?

Can someone help me get a better understanding of creating variables in C++? I'll state my understanding and then you can correct me.
int x;
Not sure what that does besides declare that x is an integer on the stack.
int x = 5;
Creates a new variable x on the stack and sets it equal to 5. So empty space was found the stack and then used to house that variable.
int* px = new int;
Creates an anonymous variable on the heap. px is the memory address of the variable. Its value is 0 because, well, the bits are all off at that memory address.
int* px = new int;
*px = 5;
Same thing as before, except that the value of the integer at memory address px is set to 5. (Does this happen in 1 step???? Or does the program create an integer with value 0 on the heap and then set it to 5?
I know that everything I wrote above probably sounds naive, but I really am trying to understand this stuff.
Others have answered this question from the point of view of how the C++ standard works. My only additional comment there would be with global or static variables. So if you have
int bar ()
{
static int x;
return x;
}
then x doesn't live on the stack. It will be initialised to zero at the "start of time" (this is done in a function called crt0, at least with GCC: look up "BSS" segments for more information) and bar will return zero.
I'd massively recommend looking at the assembled code to see how a compiler actually treats what you write. For example, consider this tiny snippet:
int foo (int a)
{
int x, y;
x = 3;
y = a;
return x + y;
}
I made sure to use the values of x and y (by returning their sum) to ensure the compiler didn't just elide them completely. If you stick that code in a file called tmp.cc and then compile it with
$ g++ -O2 -c -o tmp.o tmp.cc
then ask for the disassembled code with objdump, you get:
$ objdump -d tmp.o
tmp.o: file format elf32-i386
Disassembly of section .text:
00000000 <_Z3fooi>:
0: 8b 44 24 04 mov 0x4(%esp),%eax
4: 83 c0 03 add $0x3,%eax
7: c3 ret
Whoah! What happened to x and y? Well, the point is that the C and C++ standards merely require the compiler to generate code that has the same behaviour as what your program asks for. In fact, this program loads 32 bits from the stack (this is the contents of a, a fact dictated by the ABI on my particular platform) and sticks it in the eax register. Then it adds three and returns. Another important fact about the ABI on my laptop (and probably yours too) is that the return value of a function sits in eax. Notice, the function didn't allocate any memory on the stack at all!
In fact, I also put bar (from above) in my tmp.cc. Here's the resulting code:
00000010 <_Z3barv>:
10: 31 c0 xor %eax,%eax
12: c3 ret
"Huh, what happened to x?", I hear you say :-) Well, the compiler spotted that nothing in the code required x to actually exist, and it always had the value zero. So the function basically got transformed into
int bar ()
{
return 0;
}
Magic!
When a new variable is created, it does not have a value. It can be anything, pretty much depending on what was in that piece of stack or heap before. int x; will give you a warning if you try to use the value without setting it to something first. E.g. int y = x; will cause a warning unless you give x an explicit value first.
Creating an int on the heap works pretty much the same way: int *p = new int; calls the default constructor, which does nothing, leaving the value of *p up to chance until you set it to something explicit. If you want to make sure your heap value is initialized, use int *p = new int(5); to tell the constructor what value to copy into the memory it allocates.
Unless you initialize an int variable to zero explicitly, it is pretty much never initialized for you unless it is a global, namespace, or class static.
In VS2010 specifically(other compilers may treat it differently), an int is not given a default value of 0. You can see this by trying to print out a non-initialized int. It does allocate memory with a size of int but it is not initialized(just junk).
In both of your cases, the memory is allocated FIRST, and then the value is set. If a value is not set, you have a non-initialized part of memory that will have "junk data" inside of it and you will get a compiler warning and possibly an error when running it.
Yes, it has an address in memory but there is no valid(known) data inside of it unless you specifically set it. It vary well could be anything that the compiler recognizes as available memory to be overwritten. Since it is unknown and not reliable, it is considered junk and useless and why compilers warn you about it.
Compilers WILL set static int and global int to 0.
EDIT: Due to Peter Schneider's comment.

C++ class constant-value member -- style

My question related to style and underlying efficiency, if there's a difference at all, for effectively static member variables.
Consider:
class C {
public:
static const int const_m = 13;
static const int const_n = 17;
};
class D {
public:
enum : int { const_m = 13 };
enum : int { const_n = 17 };
};
In both cases I can write (in a main() fcxn):
int main() {
int cm = C::const_m;
int cn = C::const_n;
int dm = D::const_m;
int dn = D::const_n;
}
so the result is the same, and the coding style looks the same. In class C, the value of const_m will be put in the static section of the compiled code, and const_m will refer to the address of this value. In class D, the enum is part of the memory footprint of the class.
I've called g++ -S on both these classes and looked the trivial main() function above. I've also done this with -O0 and -O3 and I can see no different in the asm code. The key ops that correspond to the c++ code above are:
movl $13, -4(%rbp)
movl $17, -8(%rbp)
movl $13, -12(%rbp)
movl $17, -16(%rbp)
Is there a consideration that I'm missing when electing to use one style or the other?
Thanks in advance, -Jay
Edit
class C {
public:
static constexpr int const_m = 13;
static constexpr int const_n = 17;
};
ensures that const_m is compile-time available.
I don't believe you can use the static const to size an array for example, because they aren't technically required to be compile time constants.
Efficiency should definitely be the same for the two choices here. They are "compile time constants", so the compiler will be able to use the value directly without complication.
As to which is "better" from a style perspective, I think it really depends on what you are trying to achieve and what the meaning of the constants are. Enum's are definitely my choice if you have a number of different constants that are closely related, where the static const int makes more sense if it's just a single, standalone constant (max_size or magic_file_marker_value).
As touched on in the other answer, it's possible to come up with a situation where a static const int something = ...; is not a compile time constant - e.g.
static const time_t seed = time(NULL);
This would not allow you to then use it where a compile-time constant is needed [such as array sizes], because although it's a CONSTANT from many perspectives, it is not a compile time known value.

Some basic C++ questions (noob!)

I'm just beginning to learn C++ through my university course.
I'm revising for a C++ exam and I was hoping I could just ask some simple questions about things I'm not so sure on.
First of all, if I have this:
int i = 4;
What is the difference between these two lines:
int* p = &i;
int& r = i;
By my understanding, at this point both p and r are like conduits to i; changing their value will change the value of i...
Secondly, about assembly, I have a question in a past exam that is fooling me:
mov eax, dword ptr[b]
push eax
mov eax, dword ptr[a]
push eax
call printCode (411186h)
add esp,8
Q: Which of the following prototypes
when dissassembled, best match the
assembly code?
A: int printCode(int a, int b)
My question is: If the assembly is moving ptr[a] and ptr[b]... Why is the prototype not int* a, int* b?
Thank you.
The difference is that changing p's value won't change i, it will change what p points to:
p = &j;
With p, you can access, and change, i via indirection:
*p = 5;
Whereas with r, the indirection is not required, since r is an alias for i. On the flip side, this means that there is no way to change r to reference a different variable. i.e., there is no equivalent to p = &j;.
You should split the second question into a second question (if you get my drift).
int* p = &i;
p is a pointer pointing to the address of i. p will be a variable stored in your memory that contains the (virtual) memory address of i.
int& r = i;
r is a reference to i. You should think of references as aliases: you could think that r is an alias for the name i
I'd suggest you to read C++Faq chapter about references.
int* p = &i;
int& r = i;
The first statement means assigning the address of variable i to a pointer p. Here later you can change the value of the pointer p.
The second statement is "create a reference or alias r for the variable i". It is just another name for the same variable. You cannot change the reference later to point to a different variable in c++.
For the assembly snippet. I sense the snippet points to calling code. the call might have been like
printCode(*a,*b); // Here a and b are pointer to integers
So the prototype is
int printCode(int a,int b)
is right.
Ferose Khan J
What is the difference between these two lines:
int* p = &i;
int& r = i;
By my understanding, at this point both p and r are like conduits to i; changing their value will change the value of i...
The sentence is not true if taken literally. Changing p value will only make it point to a different int, changing the memory pointed to will change i:
int j = 0;
*p = 5; // equivalent to r = 5, or i = 5 (semantically, can be different in assembler)
p = &j; // changes p to point to j instead of i
You should think of pointers as proxy objects that refer you to a real instance, but that can be modified to lead to a different place. References are best understood as aliases to the object on the right hand side of the definition. You never operate on the reference, you operate on the referred object, they are the same.
References are more or less only syntactic sugars, but there are few differences between them and pointers which are described very well here.
For disassembly question.
When you say:
mov eax, dword ptr[b]
You are asking CPU to move the value from a specified address (b). So it depends what is b. If b is a int* then the answer is correct.