Gaurav K
Gaurav K

Reputation: 2975

Understanding local and global variable : C++

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

Answers (5)

kfsone
kfsone

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

See http://ideone.com/XXYu2u

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

paddy
paddy

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

zdan
zdan

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:

  1. i is set to 3
  2. the value of i is returned as a copy of i (as a temporary)
  3. i is set to 10 in A destructor
  4. the copy of i (3) is printed

func2() case:

  1. i is set to 8
  2. the value of i is returned as reference to the global variable i
  3. i is set to 10 in A destructor
  4. the current value of i is printed

func3() case:

  1. i is set to 8
  2. i is set to 10 in A destructor
  3. the value of i is returned as a copy
  4. the copy of i (10) is printed

Upvotes: 2

jogojapan
jogojapan

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

Gabe Sechan
Gabe Sechan

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

Related Questions