Reputation: 2975
Consider below code:
#include <iostream>
#include <stdexcept>
using namespace std;
int i;
class A{
public:
~A(){i=10;}
};
int func1()
{
i=3;
A Ob; // -> here local object , hence created and destroyed
return i;
}
int& func2()
{
i=8;
A obj;
return i;
}
int func3()
{
i=8;
{A obj;}
return i;
}
int main()
{
cout << "i : " <<func1() << endl;
cout << "i : " <<func2() << endl;
cout << "i : " <<func3() << endl;
return(0);
}
OutPut:
$ ./TestCPP
i : 3
i : 10
i : 10
Can someone explain why first i is 3 ? In func1()
, A Ob
is local variable and hence it is created and destroyed. When it is destroyed, it will call its destructor modifying i to 10
and I am expecting i
to be 10
, but answer shows i : 3
.
Upvotes: 1
Views: 570
Reputation: 24249
The variable "i" is global throughout the entire of your code, there is no "local" instance of it.
Objects are destroyed when they go out of scope, which is after the "return" in your functions, not before it. So the first dtor is called only after the first value of i has been returned and the function has ended.
i = 3; <-- sets i to 3
A Ob; <-- constructs object.
return i; <-- places the value "3" in the return value register.
} <-- destroys object changing future values of "i" to 10.
If you wanted to return "i" rather than the value it contains at the time of the expression "return i" you would have to make the following change:
int& func1()
{
i = 3; <-- sets i to 3
A Ob; <-- constructs object.
return i; <-- places a reference to "i" in the return value register.
} <-- destroys object changing the value of "i" to 10
I strongly encourage you to walk thru this program before and after with a debugger to better familiarize yourself with the entire process - it's the best way to solidify your understanding of what's going on.
Upvotes: 0
Reputation: 63451
Stack objects are still in scope when you call return
, so the value of i
is still 3 because the destructor for A
has not yet been called. The stack objects are removed when the function's stack unwinds, which is after the return value has been set.
Imagine if this weren't the case, if stack objects could be destroyed during the return
. How would you be able to return a local value from the function?
Response to comments
@paddy Can u explain func2 and func3 in that case ?
On the surface, func2
looks almost exactly the same as func1
, and you would be forgiven for thinking it should return 8. But the difference here is that it returns int&
instead of int
. That means a reference to i
is returned by return i;
. Even though i
is 8 when the stack starts unwinding, by the time obj
is destroyed and the return value is popped back to the caller, the value of i
is 10. Because we returned a reference, the return value is dereferenced and the current value of i
(10) is used.
For func3
it's even easier. This returns a normal int
, just like func1
. But the instance A obj;
is inside its own block scope: { A obj; }
. So it is destroyed before the return
, and the value of i
is 10 when we return from the function.
Upvotes: 4
Reputation: 29450
It has to do with whether you are returning a copy of i or a reference to it before the A destructor is called:
func1() case:
func2() case:
func3() case:
Upvotes: 2
Reputation: 69957
From the Standard (C++11, 3.7.3):
(1) Block-scope variables explicitly declared register or not explicitly declared static or extern have automatic storage duration. The storage for these entities lasts until the block in which they are created exits.
[...]
(3) If a variable with automatic storage duration has initialization or a destructor with side effects, it shall not be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 12.8.
What this means is that the lifetime of A
ends whereever the block in which it is declared ends. In the case of func1
, this is after the return-statement. In the case of func3
it is before the return-statement.
(A "block" is a piece of code enclosed in curly braces: {...}
.)
Hence, func1
evaluates the return value before the destructor of A
is called and therefore returns 3
. func3
evaluates the return value after the destructor is called and therefore returns 10
.
In the case of func2
, the order is the same as in func1
, but because it returns a reference, the value modification performed by the destructor of A
, even though it is performed after the evaluation of the return value, has an effect on the value that was returned.
Upvotes: 2
Reputation: 93542
The destructor occurs after the return statement but before the next line of the calling function. The return value is saved in a hidden variable, then the destructors and other function cleanup is called (such as returning the stack), then execution continues in the caller.
To further clarify- imagine the return line was return i+A.foo();
. You wouldn't want to call the destructor until after this line, or A wouldn't be valid to call foo on. This is why destructors are always called after the return.
Upvotes: 0