This question already has answers here:
Sell me const-correctness
(16 answers)
Closed 2 years ago.
What is the point of using the keyword const? for example when making a game, one of the first things to do is to set the width and height of it. And most of the time you'll use for example:
const int Width
and
const int height
Now I know that you should do it like that because the width and height of the screen will not change throughout the game, but what is the point of doing so ? you can do the same thing without using const and it will work just fine.
That was just an example. so what I'm confused about right now is:
What is the point of using the const keyword anywhere if you won't change the variable anyway?
Non-exhaustive list of reasons:
Software Engineering (SWE). SWE is not just programming, but programming with other people and over time.
const allows to explicitly express an invariant, which lets you and others reason about the code. As the program becomes bigger, these invariants cannot be just memorized. That's why encoding them in the programming language helps.
Optimization opportunities.
With the knowledge that certain values will not change, the compiler can make optimizations that would not be possible otherwise. To take this to the max, constexpr means that a value will be known at compile time, not just at run-time. This becomes even more important in potentially multi-threading contexts.
Example:
What kind of optimization does const offer in C/C++?
I leave out whole program analysis which would require a much longer answer and almost certainly is not applicable to generic C++ programs. But whole-program-analysis will allow reasoning of the analyzer or compiler about constness of variables as they get passed between functions, translation units and libraries.
Without const, you have to remember to not change the variable. The larger your program becomes, the harder it gets.
It also has some other useful effects:
const int a = 10;
int b[a]; // Doesn't work if `a` is not `const`.
// ...
void foo(const int &a) {};
void bar()
{
foo(42); // Doesn't work if the parameter is a non-const reference.
}
Having something declared const, compared to a value set with #define for instance, allows you to declare something that the compiler will never let you alter, but that will still keep all of the other properties of a regular variable.
In particular, it will keep a certain place in memory and a pointer on it can be obtained with « & », keeping all read-only routines that use to work on regular object compatible with it.
It's especially useful when your constant object is not a simple native type variable, but rather a complicated object spawned from a class and that still need to be initialized through a constructor.
Also remember that const is a type qualifier, than can apply not only on variable declarations, but also on arguments of a function prototype. In this particular case, this will enable your function to accept both constant or variable arguments.
Such a constant argument could be, for example, a double-quoted "string", which is const char *-typed, because the string is directly part of the code itself and defined at compilation type. Without a const qualifier, nothing could prevent your function from trying to write in it, nor warn the programmer that it's forbidden.
To stay with your example, suppose I write a game library that has a
struct game {
int width;
int height;
int area;
game(int w, int h) : width(w),height(h),area(w*h) {}
};
Now you use my library and because I did not write any documentation (evil me) you just start writing code and try what you can do with that class. You write code
#include <iostream>
int main() {
game g{3,5};
g.width = 12;
std::cout << g.width << " * " << g.height << " == " << g.area;
}
and get output:
12 * 5 == 15
You will complain that the code I wrote is broken because you get non-sense results when you use it. If however I had used const for things you are not supposed to modify:
struct game {
const int width;
const int height;
const int area;
game(int w, int h) : width(w),height(h),area(w*h) {}
};
Then you would get a nice error message that tells you that you tried to modify something that you are not supposed to modify:
prog.cc: In function 'int main()':
prog.cc:11:15: error: assignment of read-only member 'game::width'
g.width = 12;
Once you fixed your code to
#include <iostream>
int main() {
game g{3,5};
std::cout << g.width << " * " << g.height << " == " << g.area;
}
All const could be removed and the output would not change. However this is not always the case. For example member functions can have const and non-const overloads that can do different things depending on whether the method is called on a const or on a non-const object:
#include <iostream>
struct foo {
void sayHello() const {
std::cout << "I am a const object\n";
}
void sayHello() {
std::cout << "I am a non-const object\n";
}
};
int main() {
const foo f;
f.sayHello();
foo g;
g.sayHello();
}
output:
I am a const object
I am a non-const object
Conclusion:
const is mainly to ensure correctnes and to avoid mistakes. const can also be used to make const objects behave differently than non const objects. There is more to it and details you can read up eg here.
const is for a constant variable, that it means nobody should change it, or maybe for const T & passing non-trivial type as parameter, or maybe for making a pointer constant, or for value pointed from the pointer (const *P *variable)
Related
I am trying this code in Visual Studio 2015 v4.
using namespace std;
void * operator new(size_t size) {
cout << "Creating new " << endl;
void * p = malloc(size);
return p;
}
class CTest {
private:
string a;
string b;
public:
CTest( const string &&one , const string && two ) :a(move(one)), b(move(two)) {}
};
int main() {
CTest("one", "one" );
return 0;
}
This code outputs "Creating new" 4 times in Visual studio , which means it allocates memory 4 times. However following semantics it should only allocate twice ( creating 2 literals in data segment , creating one and two function argument = 2 allocs , and then moving their resource to a and b member variable )
Compiling this under g++ outputs "Creating new" twice, as it should.
Is there any settings i need to set in order for VS to follow moving semantics? It should be supported by default as far as i know.
Thanks for help.
There are several issues here:
1) std::move does not move, especially if you pass by const &&. See answers here and here.
2) Every std::string implementation I am aware of uses small buffer optimization. Such implementations will never allocate when constructed with short strings (such as "one").
3) The standard library runtime is allowed to call operator new during static initialization, for instance to setup std::cout. The allocations you see are most likely not related to the string constructor or (lack of) move.
The arguments one and two are rvalue references to constant std::string objects. How can you move from a constant object?
Drop the const qualifier for the arguments. In most cases using the const qualifier doesn't make sense for rvalue references.
Or don't use either const nor rvalue references (and the compiler should create the correct code anyway).
This question already has answers here:
Modifying a const int in C++ [duplicate]
(2 answers)
Closed 7 years ago.
I have this piece of code:
#include <iostream>
using namespace std;
class X {
public:
const int x;
X(int i) : x(i) { }
int getX() const { return x; }
};
int main()
{
const X d(45);
const_cast<X *>(&d)->x = 47;
cout << d.getX() << endl;
const int j = 3; // j is declared const
int* pj = const_cast<int*>(&j);
*pj = 4;
cout << *pj << endl; //should not work, like above
return 0;
}
As I found here, Even though const_cast may remove constness or volatility from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const or to access an object that was declared volatile invokes undefined behavior. They even proceed to provide examples below, the second one I gave, stating that it should give undefined behavior.
However, on compiling the code and running (here), the second one gives no error, and prints out 4 consistently. Whereas the first one throws error:
assignment of read-only member 'X::x'
const_cast<X *>(&d)->x = 47;
Of course, removing the const from declaration of x in X makes it work fine. However, it is also of the same type of mischief as the first one, changing a const thing through pointer after casting it const_ptr<>. But the first one works while the second one doesn't. Why so?
Both demands undefined behavior which unfortunately could mean working sometimes.
int* pj = const_cast<int*>(&j);
*pj = 4;
Also, Not all compilers are smart enough to figure out this kind of indirect manipulation.
Const-casting anything other than an actual const ptr* is probably a terrible idea, even if it does actually work most of the time.
That being said, the reason why your code doesn't compile properly is pretty straightforward: you remove the constness of the X object, but you fail to also remove the constness of the x member you're trying to modify.
Try this:
*const_cast<int*>(&(const_cast<X*>(&d)->x)) = 47;
This question already has answers here:
ampersand (&) at the end of variable etc
(5 answers)
Closed 3 years ago.
I am fairly new to programming. I am just moving on to C++ from C in my college courses, and I encountered something that I haven't seen before in C. Sometimes after the type, either in a function declaration or passing a parameter, a & immediately follows the type. For example, we use a struct called Customer in one of our projects, and some of the functions pass Customer&. Why is the ampersand after the type, as opposed to in front? Thanks!
References in C++ simply allow for a cleaner way to execute the following code:
int x = 16;
int* y = &x;
cout << *y;
Which could be written instead as
int x = 16;
int& y = x;
cout << y;
When defining functions, a reference allows a function to change the value of parameters without causing the user of the function to put an ampersand before everything. E.g.
void func( int& a )
{
a = 5;
}
void main()
{
int A = 10;
func( A );
cout << A; // Will output '5'
}
Be careful with this type of mutation, as a programmer using functions like this without checking the implementation might not realize that the function is changing the value of the parameters unless the intent is obvious. init_server(my_server) would be an example of a case where it's obvious, but to_json(my_struct) would clearly be an example where you should not be using a reference to change the struct in any way.
But, one of the most important uses of references, would be function like
int sum_vector( const vector<int>& a ) {
int sum = 0;
for( int i = 0; i < a.size(); i++ ) {
sum += a[i];
}
return sum;
}
If you tried to make sum_vector take in a vector, and you passed in a vector with 100 million entries, then it would have to copy them all over, taking forever. You could take in a pointer, but then the internal parts of the function would have to constantly dereference, and it must called with sum_vector(&myvec), which is more annoying than sum_vector(myvec). In this way, using a const reference, you can prevent the highly inefficient copying of the whole vector into the function body, while keeping syntax neat. Using const lets you reassure yourself that you're not going to change the vector that you were given. And, it also assures the user of your function that you won't change it. Similarly, void to_json(const some_struct&) would be a better function definition as it ensures you won't change the user's data.
I'm creating a method and one parameter of that method asks for a reference of an unsigned int, but I want to put a default value on that parameter. For example:
#include <iostream>
using namespace std;
class A {
public:
void sender();
private:
unsigned int score = 10;
};
class B {
public:
void receiver(unsigned int & score);
};
void A::sender() {
cout << "Before: " << score << endl;
B b;
b.receiver(score);
cout << "After: " << score << endl;
}
void B::receiver(unsigned int & score) {
score = 100;
}
int main() {
A a;
a.sender();
return 0;
}
Live demo: in here
The error happen when I do this:
void receiver(unsigned int & score = 10u);
And the compiler returns:
error: could not convert ‘10u’ from ‘unsigned int’ to ‘unsigned int&’
Live demo: in here
You cannot assign a literal1 to a non-const reference.
There are two scenarios where one will suit your situation:
You intend to modify the argument being passed to receiver()
If that is the case, the use a non-const reference (unsigned int & score) without the default parameter. In situations where you pass a literal or temporary object to it, then it will result in a compiler error.
a.receiver(10); // Error
The above wouldn't make any much sense considering that you want to modify that argument (you wouldn't see the modification if C++ had allowed that2).
You intend to just use the parameter in a read-only fashion
Just use plain, non-reference, unsigned int, because const unsigned int& score is just a pain to write. In cases where you determine that an object is expensive to copy, then that is the time where you should have the parameter a const reference.
UPDATE: There are some cases where you want to modify something, but that something may or may not exist. In cases like that, you may want to use a non-owning pointer as the parameter.
// Declaration
void receiver(unsigned int* score = nullptr);
void B::receiver(unsigned int* score) {
if(score) *score = 100;
}
...
a.receiver(); // Uses the default parameter
unsigned int x;
a.reciever(&x);
In this case, it only assigns to score when it points to some (assumed) valid variable. Pointers aren't that bad at all.
UPDATE 2: However, as #Potatoswatter have pointed out, you may be better off with function overloading.
void B::receiver() {
// Do something else
}
void B::receiver(unsigned int& score) {
score = 100;
}
You should use this in cases where you want your overloads to behave differently on different parameters.
However again, I prefer the first, non-default parameter option, rather than the pointer option and the overloading option, as it requires that the caller provide a parameter, which is much better when you are modifying something through a function.
UPDATE 3: You should also consider to have your function return the value instead of modifying it through a parameter. In cases where you don't need the current state of the object being modified, having a function return a value is much more intuitive. One caveat though is that the caller may forget to capture (assign) the return value, which could be dangerous if you are using that value as some resource ID to free something up.
1 And in general, a temporary object.
2 And the universe would probably blow up if 10 was magically transformed into 100 ;)
You want the argument type to be const unsigned int&. Otherwise, you can do something crazy, like try to assign 10 = 20, which doesn't make sense.
And that happens to be exactly that you did. The score = 100 line doesn't seem to be what you actually meant.
the value "10" isn't a reference- it's a value. By having a by-reference parameter, it must be called with a reference. Using a default parameter means you could call the function without specifying the parameter and the compiler would use the default.
Similarly, calling b.receiver(10); is not valid, but
int someInt = 10;
b.receiver(someInt);
is valid.
Can we cast a const int into an int in C++ without declaring a new variable?
This option is available in VS but how can it be used in other compilers such as Xcode, code blocks, etc?
const int a = 5 ;
int (a) ++ ;
a is const. You can't legally remove the constness to mutate the variable in any compiler. What you're seeing in VS is that it's letting you create an unnamed temporary and incrementing THAT.
TL;DR: You can change the value of a const variable but you can't guarantee your code will behave as though you did.
There is, of course, a way to do it, but first lets make sure you understand what you're asking to do:
const int a = 5;
This tells the compiler that there is a value, 5, which you want to refer to as "a", for example so you can do:
const int MaxNameLen = 5;
char name[MaxNameLen + 1];
or
const float pi = 3.14;
return pi * radius;
Compiled without optimization, this will probably produce code which injects a variable like any other and uses it as you would expect.
But by calling the variable "const" you've signed a contract with the compiler: Behave as tho this value does not change. So you can do, for example:
int a = 5;
*(static_cast<int*>(&a))++;
But as far as the compiler is concerned, a did not change. It is free to carry on behaving as tho it didn't. So if it loaded it into a register, if it sized something based on it, it is free to just go ahead and assume it can use the value "5" wherever it sees "a". For example:
#include <iostream>
using namespace std;
int main()
{
const int a = 5;
(*const_cast<int*>(&a))++;
std::cout << "a = " << a << std::endl;
}
might print 5 or it might print 6, depends on which compiler, which settings and the context of the code. Variable "a" has an address but you told the compiler it wouldn't change, so it may already have pushed it onto the stack or loaded it into a register.
Where this is going to hurt you worst is in highly optimized because the compiler is going to produce instructions and ordering based on your promise that "a" does not change.