I am well aware that modifying a function's argument that is passed by value is ineffective outside of the C/C++ function, but compilers allow it - but what happens? Is a local copy made of the argument and that is modifiable within the function?
#include <stdio.h>
void doSomething( int x )
{
x = 42;
printf( "The answer to Life, the Universe and Everything is (always): %i!\n", x );
}
int main( int argc, char **argv )
{
int a = 0;
doSomething( a );
return -a;
}
Now this always exits without error, but where in the scheme of things (memory space) is the value represented in the function as x kept?
I imagine that should the (combined declaration and definition) begin:
void doSomething( const int x )
I would get my wrists slapped by any half-decent compiler.
For the function doSomething(), x is local to the function. It has the similar scope of any other variable defined at the beginning of the function body.
In general terms, x exists only in the scope of doSomething() function. x is defined once doSomething() is called (and the argument is passed) and destroyed once the control returns. As long as the function call is being executed (i.e., the variable remains in scope), the parameter(s) are the same as any other variable, only initialized by the arguments supplied in the function call.
Quoting C11, chapter ยง6.2.1, Scopes of identifiers
[...] If the declarator or type specifier that
declares the identifier appears inside a block or within the list of parameter declarations in
a function definition, the identifier has block scope, which terminates at the end of the
associated block. [...]
As you are already aware, x being the local copy of the actual argument passed to function call, any changes made to x inside the function will not reflect into the caller (actual argument), but there's no reason for the compiler to complain as long as the operation(s) on x inside the function is (are) valid.
As others have explained, x is local in function doSomething, any modifications only affect the local copy of the argument.
Note however that C++ allows passing by reference: a very small change in the definition of doSomething() would have significant consequences for this program:
void doSomething( int& x ) {
x = 42;
printf( "The answer to Life, the Universe and Everything is (always): %i!\n", x );
}
With the above function definition, variable a in main would indeed have its value changed to 42. Since the code in main() is identical, this C++ feature can lead to confusing code, especially for a C programmer.
A value parameter of a function is effectively a local variable of the function, except that it is initialised in the function call. So these:
void f( int n ) {
n++;
}
and:
void g() {
int n = 0;
n++;
}
are effectively the same, if the call to f() was made as f(0). In both cases, the variable will be discarded on function exit.
The formal parameter x is a separate object in memory from the actual parameter a, so any changes to x are not reflected in a.
Value x is local and is kept in stack. Each function has it own part of stack which is reserved when program enters function.
Value x will be located in this part of stack. And it is valid only in scope of function which defined it.
If you change x it will be changed only for function where it is defined.
if function ends (return from function), stack which was reserved for function is destroyed so also value x. So x won't be accessible because it doesn't exists anymore.
Related
Today I encountered a very unintuitive behavior (for me, at least) in C++11 lambdas. The code in question is the following:
#include <stdio.h>
auto sum(int x) {
return [&x](int y) {
return x + y;
};
}
int main() {
int a = sum(2)(3);
printf("%d\n",a);
}
Instead of printing 5, this prints gibberish. Actually, at least in my version of GCC, if I turn on the -O2 optimization flag, it actually prints 5. Since the output depends on the optimization level of the compiler, it is undefined behavior. After a while, I think I understood what is happening.
When the function sum is called, a stack variable corresponding to the argument x is set to 2, then the function sum returns, and this stack variable might be overwritten by anything that the compiler needs to put there to execute following code, and by the time the lambda eventually gets executed, the place where x was no longer holds 2, and the program adds 3 to an arbitrary integer.
Is there any elegant way to do currying in C++ guaranteeing that the variable gets captured correctly?
int x has a limited lifetime. References to automatic storage variables (what you call "the stack") are only valid over the variable's lifetime. In this case, only until the end of the stack frame (the scope) where the variable exists, or the function for function arguments.
[&] captures any mentioned ("local") variable by reference, except this (which is captured by value if used or implicitly used). [=] captures any mentioned variable by value. [x] would capture x explicitly, and [&x] by reference explicitly. In C++17, [*this] also works.
There is also [x=std::move(x)], or [blah=expression].
In general, if the lambda will outlive the current scope don't use [&]: be explicit about what you capture.
Will the two function specifications below always compile to the same thing? I can't see that a copy would be needed if you're using const. If they aren't the same, why?
void(const int y);
void(const int& y);
Not the same. If the argument changes after it's passed (e.g. because it's changed by another thread), the first version is unaffected because it has a copy. In the second variant, the function called may not change the argument itself, but it would be affected by changes to y. With threads, this might mean it requires a mutex lock.
Without optimization ... this is not the same.
The first line of code gets a copy of the value passed into this function.
The second line of code gets the reference of the variable and your function will read the value always directly from the calling location variable .
In both cases the compiler is informed (by the keyword const), that these variables (inside the function) MUST not be modified. If there are any modifications in the function, an error will be generated.
The & specifies that the object is passed by reference (similar to passing by pointer at least on the assembly level). Thus
void fval(type x)
{
// x is a local copy of the data passed by the caller.
// modifying x has no effect on the data hold by the caller
}
type a;
fval(a); // a will not be changed
void fref(type &x)
{
// x is a mere reference to an object
// changing x affects the data hold by the caller
}
type b;
fref(b); // b may get changed.
Now adding the const keyword merely expresses that the function promises not to change the object.
void fcval(const type x)
{
// x is a local copy of the data passed by the caller.
// modifying x is not allowed
}
type a;
fcval(a); // a will not be changed
void fcref(const type &x)
{
// x is a mere reference to an object
// changing x is not allowed
}
type b;
fcref(b); // b will not be changed
Since a copy may be expensive, it should be avoided if not needed. Therefore, the method of choice for passing a constant object a la fcref (except for builtin types when fval is fast).
Today I encountered a very unintuitive behavior (for me, at least) in C++11 lambdas. The code in question is the following:
#include <stdio.h>
auto sum(int x) {
return [&x](int y) {
return x + y;
};
}
int main() {
int a = sum(2)(3);
printf("%d\n",a);
}
Instead of printing 5, this prints gibberish. Actually, at least in my version of GCC, if I turn on the -O2 optimization flag, it actually prints 5. Since the output depends on the optimization level of the compiler, it is undefined behavior. After a while, I think I understood what is happening.
When the function sum is called, a stack variable corresponding to the argument x is set to 2, then the function sum returns, and this stack variable might be overwritten by anything that the compiler needs to put there to execute following code, and by the time the lambda eventually gets executed, the place where x was no longer holds 2, and the program adds 3 to an arbitrary integer.
Is there any elegant way to do currying in C++ guaranteeing that the variable gets captured correctly?
int x has a limited lifetime. References to automatic storage variables (what you call "the stack") are only valid over the variable's lifetime. In this case, only until the end of the stack frame (the scope) where the variable exists, or the function for function arguments.
[&] captures any mentioned ("local") variable by reference, except this (which is captured by value if used or implicitly used). [=] captures any mentioned variable by value. [x] would capture x explicitly, and [&x] by reference explicitly. In C++17, [*this] also works.
There is also [x=std::move(x)], or [blah=expression].
In general, if the lambda will outlive the current scope don't use [&]: be explicit about what you capture.
Lets say I have following function, and it has an argument which is type T. What is life time of that argument.
int* f()
{
int x=0;
int* ptr=&x;
return ptr; //i know this is undefined behavior.
}
So in f() function when it s called, local expressios will run and end of scope pointed value will be deleted. But my question is for following function
void f2(int* y)
{
}
int main()
{
int p=0;
f2(&p);
cout<<p<<endl;
return 0;
}
Here, when we call f2() when that parameter int* y will be deleted? And so if its deleted logicaly pointed value will be deleted which is p, why I can see value of p same using cout? So when f2's argument will be deleted? when function's end scope? or what?
In void f2(int* y), you have a copy of a pointer. The lifetime of that pointer object y, extends to the end of the function f2.
In your main function, you have an integer p. The lifetime of p extends to the end of main.
When calling f2(&p), a temporary pointer is created to be passed to f2. It does not modify the lifetime of p. So, when f2 returns, the temporary pointer is no longer in scope, however p is still in scope (and therefore, valid).
All of the variables shown have automatic storage duration and do not require explicit "deletion".
The function does no memory management on arguments you pass it unless the argument is passed by value (technically everything is passed by value in c++, except a reference, but in the case of a pointer there isn't much to clean up). In the case of your code p is destructed when main's scope ends. Remember this is because p has automatic storage if it had dynamic storage it would be deleted only when you call delete on it.
Now in general there is no reason to pass around an automatic variable as a ptr because c++ has this great thing called pass by reference
void f2(int& y)
This is what you should be doing in most cases
A function parameter is just a local variable in the block scope of the function body. The difference between a function parameter and an ordinary block scope variable is that before the body begins executing, the function parameter is initialized from the corresponding function call expression.
The lifetime of the variable y extends only over the execution of the body of function f.
The object which the pointer object named y points to has a lifetime which is completely unrelated to y.
Pointers are not "deleted" automatically (in the sense that the delete operator is applied to them) at end-of-scope. The variable containing the address itself will be deleted, but the data it points to will not.
You might look at std::unique_ptr, which does what you're describing.
p is created on stack when main is entered. you call f and pass the address of p to it. The f's parameter y gets this address. y is also stored on stack. When f returns, y is deleted because it is a local variable, but p still exists and you print its value. Similar to y, the local variable p is deleted when main exits.
void execute(int &x,int y=100)
{
x=x+y;
cout<<x<<endl;
}
void main()
{
int a=5,b=6;
execute(b);
}
will the following program work in spite of not assigning a default value to the x(formal parameters in the function prototype).
Yes, it will work. By not assigning the default value to x you are forcing the caller to pass a value as the parameter. When you do execute(b) in main you are binding the reference x with actual parameter 'b' and since you have not passed any value to variable 'y' the default value will be used.
Firstly, there's no such thing as "function prototype" in C++. "Prototype" is a term from C parlance, which has no meaningful application in C++. What you have here is a function declaration, which also happens to be a function definition.
Secondly, it appears you are asking whether it is required to specify default arguments for all function arguments in C++, right? If so, the answer is no, there's no requirement to specify default arguments for all function arguments.
Thirdly, it is supposed to be int main, not void main.
You run execute(b), meaning that execute will run b = b + 100 (y is 100 since you didn't pass it in, and it got the default value), print out 106 and b will be modified back in main, since it's taken by reference.
I think you're confused as to how a function works. You're passing the value for x into it (well, a reference to an int not the actual value) so ... yes, that works.
By providing a default value for y ( int y=100 ) you're making it so the function can be called without passing the second argument to it. If called with a single argument, y will be assigned the value 100.
int a=5,b=6;
execute(b);
Once inside execute(), the initial value of x is 6, and y is 100.