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.
Related
I got this declaration from https://en.cppreference.com/w/cpp/language/scope, but don't know how to parse this declaration even there is a comment below.
my questions is
how to parse the declaration statement (I see it as a function pointer to a function protocol like "int[3] foo(int n)" or "int foo(int n)[3] --- they are illegal in C++ )? Then, how can I construct a concrete function which can be assigned to this function pointer? Thanks.
const int n = 3;
int (*(*f2)(int n))[n]; // OK: the scope of the function parameter 'n'
// ends at the end of its function declarator
// in the array declarator, global n is in scope
// (this declares a pointer to function returning a pointer to an array of 3 int
It's a pointer to a function taking an int and returning a pointer to an int array of size three.
All the comment is saying is that there are two n identifiers in play here. The [n] (in array declarator) is using the const int 3, not the parameter to the function (which is in the function declarator).
Starting in the middle, with each segment being included in the subsequent bullet point as ...:
f2 is a pointer, (*f2).
It's a pointer to a function taking an integer, ...(int).
It returns a pointer to an int array of size three, int (*...)[3].
You can form a concrete function for it as per the following complete program, which output the first element, 42:
#include <iostream>
const int n = 3;
int (*(*f2)(int n))[n];
int (*g2(int))[n] {
static int x[::n] = { 42 }; // Use outer n, not the parameter.
return &x; // since C++ has no VLAs. This
// means parameter is not actually
// needed in this test case, though
// it may be in more complicated
// tests.
}
int main() {
f2 = &g2; // Assign concrete function to pointer.
auto y = f2(3); // Call via pointer, get array.
std::cout << *(y[0]) << '\n'; // Deref first element to get 42.
}
Having said that, I would be rather curious if one of my colleagues submitting something like that for a code review, at least without a large comment explaining it. Although seasoned developers may be able to work it out, those less experienced may have trouble.
And, in fact, even seasoned developers shouldn't have to work it out, especially given it took me a few minutes.
C++ has a very expressive type system which can easily build something like this up in parts, so you don't have to experience migraines trying to work it out. For something like this, I'd be using std::vector (or std::array) unless there was a compelling case for the added complexity caused by more basic types.
You can create a type for pointer to an array of 3 int
typedef int (*array_with_size_n)[n];
and then use it as return type
const int n = 3;
int (*(*f2)(int n))[n];
int arr[n];
array_with_size_n func(int n)
{
return &arr;
}
int main()
{
f2 = &func;
return 0;
}
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)
i have written this little program to explain my point and my variable a remains unchanged it prints 4. I later learned that I need to use pointers or references; why is that?
#include <iostream>
void setToTen(int x) { x = 10; }
int main(){
int a = 4;
setToTen(a);
std::cout << a << std::endl;
}
In C++ arguments to functions are passed by value. This means that when you write
setToTen(a);
the parameter int x in setToTen is given a copy of the value stored in the variable a. In other words, you're not actually handing off the variable a into the setToTen function. Instead, you're giving a copy of that value to setToTen, so the changes made in that function affect the copy rather than the original.
On the other hand, if you change setToTen so that it takes its parameter by reference, like this:
void setToTen(int& x) {
x = 10;
}
the story is different. Here, calling setToTen(a) essentially hands the variable a into the function setToTen, rather than a copy of the value. That means that changes made to the parameter x in setToTen will change the variable a.
Your code requests a copy of x by having the signature void setToTen(int x).
Being able to take things by copy means that reasoning about the behavior of a function is far easier. This is true both for you, and for the compiler.
For example, imagine this:
int increase_some( int x, int y, int z ) {
for (int i = 0; i < y; ++i )
x+=z;
return x;
}
because x y and z are copies, you can reason about what this does. If they where references to the values "outside" of increase_some, the bit where you x+=z could change y or z and things could get crazy.
But because we know they are copies, we can say increase_some returns x if y<=0, and otherwise returns x+y*z.
Which means that the optimizer could change it to exactly that:
int increase_some( int x, int y, int z ) {
if (y<=0) return x;
return x + y*z;
}
and generate that output.
This is a toy example, but we took a complex function and turned it into a simple one. Real optimizers do this all the time with pieces of your complex function.
Going one step further, by taking things by immutable value, and never touching global state, we can treat your code as "functional", only depending on its arguments. Which means the compiler can take repeated calls to a function and reduce them to one call.
This is so valuable that compilers will transform code that doesn't have immutable copies of primitive data into code that does before trying to optimize -- this is known as static single assignment form.
In theory, a complex program with lots of functions taking things by reference could be optimized this same way, and nothing be lost. But in practice that gets hard, and it is really easy to accidentally screw it up.
That is the other side; making it easier to reason about by people.
And all you have to embrace is the idea of taking arguments by value.
Function parameters are function local variables that are not alive after exiting function.
You can imagine the function definition and its call
int a = 4;
setToTen(a);
//...
void setToTen(int x) { x = 10; }
the following way
int a = 4;
setToTen(a);
//...
void setToTen( /* int x */ ) { int x = a; x = 10; }
As it is seen within the function there is declared a local variable x which is initialized by the argument a. Any changes of the local variable x do not influence on the original argument a.
If you want to change the original variable itself you should pass it by reference that is the function will deal with a reference to the variable. For example
void setToTen(int &x) { x = 10; }
In this case you can imagine the function definition and its call the following way
int a = 4;
setToTen(a);
//...
void setToTen( /* int x */ ) { int &x = a; x = 10; }
As you see the reference x is as usual local. But it references the original argument a. In this case the argument will be changed through the local reference.
Another way is to declare the parameter as pointer. For example
void setToTen(int *x) { *x = 10; }
In this case you have to pass the original argument indirectly by its address.
int a = 4;
setToTen( &a );
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;
What is more efficient: Call by pointer or by value? I think it is call by pointer, because passing a pointer to a variable does not use as much memory as creating a copy of a variable. Am I wrong?
main(){
int a, b;
a = 10;
b = 5;
gcf(&a, &b);
return 0;
}
int gcf(int* c, int* d){
int val1=*c;
int val2=*d;
//...
}
In nearly all code, as long as we're dealing with small/simple objects, the overhead of copying the object, vs. passing it as a pointer or reference is pretty small.
Obviously, if we make a std::string with a large chunk of text in it, it will take quite some time to copy it, relative to just passing a reference.
However, the primary objecting ANY TIME when writing code is to focus on correctness. If you have "large" objects, then use const Type &val if the value is not being modified - that way, you can't accidentally modify it. If the object is to be modified, then you NEED to use a reference or pointer to get the updates back to the caller of the function.
It is entirely possible to make code that runs noticeably slower with a reference than with a value. I was once looking into the performance of some code that we were working on, and found a function that looked something like this:
void SomeClass::FindThing(int &thing)
{
for(thing = 0; someVector[thing] != 42; thing++)
;
}
It really looks rather innocent, but since each update of thing means an indirect memory access [at least in the compiler we used, which was certainly not "rubbish"], it was taking quite a lot of time out of the entire process [it was also called twice as much as necessary].
I rewrote it as:
void SomeClass::FindThing(int &thing)
{
for(int i = 0; someVector[i] != 42; i++)
;
thing = i;
}
And the function ran about 4x faster. Taking out the second, unnecessary call, as well, and we ended up with about 30% faster runtime. This was in a "fonts benchmark", and this was one out of a several dozen functions involved in the "draw fonts to screen". It's scary how a simple, innocent looking function can make a BIG difference to performance.
For types smaller than the size of a pointer (e.g. int), passing by value is more efficient.
For types bigger than the size of a pointer (e.g. most struct or class instances), passing by reference is probably more efficient (only "probably" because on top of the cost of passing the parameter, potentially constructing an object, you incur the cost of dereferencing your parameter every time you use it).
More details about passing-by-value vs. passing-by-reference can be found in this question. More details about reference vs. pointer arguments can be found in that question.
In your example of code snippet
main(){
int a, b;
a = 10;
b = 5;
}
int gcf(int* c, int* d){
int rem;
int val1=*c;
int val2=*d;
//...
}
there is no any sense to pass variables a and b to the function indirectly using pointers if you are not going to change them. In this case the code is ineffective because that to get values of *c and *d the compiler will need to generate more instructions.
And you are wrong saying that
passing a pointer to a variable does not use as much memory as
creating a copy of a variable. Am I wrong?
Usually pointers are equal to or even larger than the size of type int. For exaple in a 64-bit system sizeof( int ) can be equal to 4 while sizeof( int * ) can be equal to 8.
There is a sense to pass an object indirectly by pointers (usually in C programs) when the size of the object is much larger than the size of the pointer.
In C++ instead of pointers usually references are used.
For example
#include <iostream>
#include <string>
inline void print_reverse( const std::string &s )
{
std::cout << std::string( s.rbegin(), s.rend() ) << std::endl;
}
int main()
{
std::string s( "Hello World" );
print_reverse( s );
}
Here const std::string &s defined reference to an object of type std::string.