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.
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.
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.
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:
i is set to 3
the value of i is returned as a copy of i (as a temporary)
i is set to 10 in A destructor
the copy of i (3) is printed
func2() case:
i is set to 8
the value of i is returned as reference to the global variable i
i is set to 10 in A destructor
the current value of i is printed
func3() case:
i is set to 8
i is set to 10 in A destructor
the value of i is returned as a copy
the copy of i (10) is printed
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.
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.
Related
The code is :
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A" << endl; }
~A() { cout << "A::~" << endl; }
};
class B
{
public:
B() { cout << "B::B" << endl; }
~B() { cout << "B::~" << endl; }
};
int main()
{
B b;
static A a;
return 0;
}
The output is :
B::B
A::A
B::~
A::~
The scope of non-static object b and the scope of static object a ends at the end of main() function.
Question : Why is the order of constructors is same as the order of destructors ?
Static local variables will be destroyed at program exit.
The destructor for a block-scope static variable is called at program exit, but only if the initialization took place successfully.
So b will be destoryed firstly at the end of main(), a will be destroyed after that.
For the initialization,
are initialized the first time control passes through their declaration
So b will be initialized firstly in main(), then a gets initialized.
Because they have different lifespans. A is declared as function-local static variable.
Object created by declaration of automatic function-local variable got lifespan which begins before any use of that object and ends with the most nested code block (braces block) containing that declaration. In your case that's function main() body.
Object created by declaration of static function-local variable begins to exist after execution flow had entered the most nested code block containing that declaration and before any use of that object.
It got process-wide life span (stops to exist at std::atexit()), which happens after the function main() will be exited.
SO they are created in this particular case in order of declaration, but A will get destroyed way later. If your function was called twice, you'd see that B would be created twice but A only once. If function's flow would somehow omit either declaration, by if() statement or by returning early, the order of their creation of would change or both may be omitted.
It's implementation specific detail, but usually destruction of function-local statics implemented in same way as destruction of global objects, by call to a library function that lies under implementation of std::atexit, adding the address of destructor bound with value of pointer to object itself, but the execution may be concurrent (or may be not) with result of user's calls of std::atexit.
As addition to already existing answers, lets take a more phenomenological approach. Consider a small change on your example:
void foo() {
B b;
static A a;
}
int main() {
foo();
foo();
}
I assume you know that a is initialized only once and on the second call we get the exact same object a, because it is declared as static. Hence, it cannot be destroyed during or directly after the first call to foo. The expected first part of the output is
B::B // first call to foo()
A::A
B::~
B::B // second call to foo()
// no second call to A::A !
B::~
a can only be destroyed when your program terminates, otherwise you could not "reuse" it when calling the function again (thats why I had to modify the example, you cannot call main). As other answers explain in great detail, this happens after main returns. Hence last line of output will be
A::~
I have the following code:
#include <stdio.h>
class Foo {
public:
int a;
~Foo() { printf("Goodbye %d\n", a); }
};
Foo newObj() {
Foo obj;
return obj;
}
int main() {
Foo bar = newObj();
bar.a = 5;
bar = newObj();
}
When I compile with g++ and run it, I get:
Goodbye 32765
Goodbye 32765
The number printed seems to be random.
I have two questions:
Why is the destructor called twice?
Why isn't 5 printed the first time?
I'm coming from a C background, hence the printf, and I'm having trouble understanding destructors, when they are called and how a class should be returned from a function.
Let's see what happens in your main function :
int main() {
Foo bar = newObj();
Here we just instantiate a Foo and initialize it with the return value of newObj(). No destructor is called here because of copy elision: to sum up very quickly, instead of copying/moving obj into bar and then destructing obj, obj is directly constructed in bar's storage.
bar.a = 5;
Nothing to say here. We just change bar.a's value to 5.
bar = newObj();
Here bar is copy-assigned1 the returned value of newObj(), then the temporary object created by this function call is destructed2, this is the first Goodbye. At this point bar.a is no longer 5 but whatever was in the temporary object's a.
}
End of main(), local variables are destructed, including bar, this is the second Goodbye, which does not print 5 because of previous assignment.
1 No move assignment happens here because of the user-defined destructor, no move assignment operator is implicitly declared.
2 As mentioned by YSC in the comments, note that this destructor call has undefined behavior, because it is accessing a which is uninitialized at this point. The assignment of bar with the temporary object, and particularly the assignment of a as part of it, also has undefined behavior for the same reasons.
1) It's simple, there are two Foo objects in your code (in main and in newObj) so two destructor calls. Actually this is the minimum number of destructor calls you would see, the compiler might create an unnamed temporary object for the return value, and if it had done that you would see three destructor calls. The rules on return value optimization have changed over the history of C++ so you may or may not see this behaviour.
2) Because the value of Foo::a is never 5 when the destructor is called, its never 5 in newObj, and though it was 5 in mainit isn't by the time you get to the end of main (which is when the destructor is called).
I'm guessing your misunderstanding is that you think that the assignment statement bar = newObj(); should call the destructor, but that's not the case. During assignment an object gets overwritten, it doesn't get destroyed.
I think one of the main confusions here is object identity.
bar is always the same object. When you assign a different object to bar, you don't destroy the first one - you call operator=(const& Foo) (the copy assignment operator). It is one of the five special member functions that can be auto-generated by the compiler (which it is in this case) and just overwrites bar.a with whatever is in newObj().a. Provide your own operator= to see that/when this happens (and to confirm that a is indeed 5 before this happens).
bar's destructor is only called once - when bar goes out of scope at the end of the function. There is only one other destructor call - for the temporary returned by the second newObj(). The first temporary from newObj() is elided (the language allows it in this exact case because there is never really a point to creating and immediately destroying it) and initializes bar directly with the return value of newObj().
I am currently reading the second edition of C++: A Beginner's Guide by Herbert Schildt.
In Module 9.4, he talks about returning objects:
Just as objects can be passed to functions, functions can return objects. To return an object, first declare
the function as returning a class type. Second, return an object of that type using the normal return
statement. The following program has a member function called mkBigger( ). It returns an object that
gives val a value twice as large as the invoking object.
This is the 'following program' he mentions:
// Returning objects.
#include <iostream>
using namespace std;
class MyClass {
int val;
public:
// Normal Constructor.
MyClass(int i) {
val = i;
cout << "Inside constructor\n";
}
~MyClass() {
cout << "Destructing\n";
}
int getval() { return val; }
// Return an object.
MyClass mkBigger() {
Myclass o(val * 2); // mkBigger() returns a MyClass object.
return o;
}
};
void display(MyClass ob)
{
cout << ob.getval() << '\n';
}
int main()
{
cout << " Before Constructing a.\n";
MyClass a;
cout << "After constructing a.\n\n";
cout << "Before call to display.\n";
display(a);
cout << "After display() returns.\n\n";
cout << "Before call to mkBigger().\n";
a = a.mkBigger();
cout << "After mkBigger() returns.\n\n";
cout << "Before second call to display.\n";
display(a);
cout << "After display() returns.\n\n";
return 0;
}
This gives us the following output:
Before Constructing a.
Inside constructor
After constructing a.
Before call to display.
10
Destructing
After display() returns.
Before call to mkBigger()
Inside constructor
Destructing
Destructing
After mkBigger() returns.
Before second call to display.
20
Destructing
After display() returns.
Destructing
Schildt then goes on to explain that the reason there are two 'Destructing' messages during the mkBigger() call is because of the fact that:
when an object is returned by a function, a temporary object is automatically created, which holds the return value. It is this object that is actually returned by the function. After the value has been returned, this object is destroyed.
I was actually surprised there wasn't 3 'Destructing' messages. I have the following issue: Given the definition of mkBigger(), a new MyClass instance is created, and it is that instance that is returned and placed in the address of a. Thus, when doing
a = a.mkBigger();
My impression is thus that the original object previously held in a is no longer referenced by a. Is this correct? If so, I then have the following issues:
I was told C++ has some minute notions of garbage collection. Would that object thus be garbage-collected? where is this object now? Is this an example of the possible feared memory leaks that many mention when talking about the 'dangers' of C++?
One of the destructor in mkbigger() is called on o, the MyClass instance passed in by value; it goes out of scope at the end of the function. The other is called on the temporary copy of o returned when it is destroyed. What else goes out of scope? Not a in main(); therefore you should not expect a third destructor to be called. C++ does not provide garbage collection outside of calling destructors when automatic objects go out of scope.
Unlike some other modern languages, a does not "hold a reference" to an object; a is the object, in that it is a certain number of bytes holding the raw data members. When you do a = a.mkBigger();, MyClass's default assignment operator is called, which simply copies the val inside the temporary object on the right hand side into the val inside a, overwriting the value that was already there. a = a.makeBigger() would be equivalent to a.val = a.makeBigger().val if val were public.
Memory leaks occur when you use new to allocate memory and then fail to use delete to deallocate that memory. For classes that do this internally, you must write at least your own copy constructor, assignment operator, and destructor.
My friend told me C++ allows us to call a member function even if the instance is destroyed from memory. So I write the code below to verify it, but why the value of a can be extracted even after the object was destroyed? I thought there would be a segment fault.
#include <iostream>
class Foo{
public:
Foo(int a = 0){
std::cout << "created" << std::endl;
this->a = a;
}
~Foo(){
std::cout << "destroyed" << std::endl;
}
Foo *f(){
std::cout << "a=" << a << std::endl;
return this;
}
private:
int a;
};
Foo *iwanttocallf(int i){
return ((Foo)i).f();
}
int main(){
for(int i = 0; i < 3; i++)
iwanttocallf(i)->f();
}
Output from my Macbook Air:
created
a=0
destroyed
a=0
created
a=1
destroyed
a=1
created
a=2
destroyed
a=2
Usually compilers are implementing the member function call as a call to a regular c function with the first argument a pointer to the object (gcc does it like that as far as I know). Now if your pointer is pointing to one destroyed object it doesn't mean that the memory where the a has been stored will be changed, it might be changed. So it is undefined behavior in general. In your case you got a value of a but maybe next time with a different compiler or different code you will crash. Try to use placement new operator then set a value of 'a' = 0 in destructor... and follow the memory where the object is stored.
"My friend told me C++ allows us to call a member function even if the member is destroyed from memory"?
I don't know what your friend is trying to say. But you call member function on some object of a class
unless it's a static member. So, if you delete that object from memory, how could you call any function of that class on that object. It's an undefined behavior.
This is covered in §12.7 [class.cdtor]:
[..] For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor
finishes execution results in undefined behavior.
As other people have told, this involves undefined behavior, and any result is possible. I'll try to explain why you encountered this particular result (stuff working normally).
Objects in C++ are represented by contents of memory. When an object is destroyed, its
destructor is executed, but the memory still contains the previous value. The output operation outputs the value taken from memory (which is now "free" - doesn't belong to any object) - if there is not much stuff going on between the destructor call and the output, the old value will remain.
However, if you change your code to add some calculations, the bug will be evident. For example, I added the following function that simulates some calculations:
int do_stuff()
{
int result = 0;
int x[3] = {0};
for (auto& n: x)
{
n = rand();
result ^= n;
}
return result;
}
I also added a call to this function:
Foo *f(){
std::cout << "foo1: a=" << a << std::endl;
do_stuff();
std::cout << "foo2: a=" << a << std::endl;
return this;
}
I got the output:
foo1: a=0
foo2: a=424238335
This clearly shows that it's not safe to expect anything consistent when dealing with deleted objects.
By the way, some debuggers overwrite the memory that deleted objects occupied with a special value like 0xcdcdcdcd - to make some sense out of this kind of unpredictable behavior. If you execute your code under such a debugger, you will see garbage printed, and will immediately know that your code is buggy.
Following is a simple function definition that returns an integer
int myFunc()
{
int localVar = 99;
return localVar;
}
and it called in main as
int main()
{
int y = myFunc();
cout << y << endl;
return 0;
}
This works as it is expected. I want to know why?
localVar is a local variable and its value is allocated in stack. It goes out of scope as soon as the function ends. So, localVar would have gone out of scope in the call int y = myFunc(); How/Why is it still able to return the correct value?
Your function is returning a copy of the value – that's what "return by value" means.
int y = myFunc(); will copy the bytes of the value from a temporary location used by the function invocation to your local variable.
It would only fail if you return the address of the local variable.
There are three things to be aware of here:
The object localVar
The return value of myFunc
The object y
Yes, localVar goes out of scope at the end of myFunc. However, before that happens, its value is being copied into the return value of myFunc (that's what the return statement does). Then, this return value is being copied into the object y. It doesn't matter that localVar is now gone - you have a copy of it.
That's exactly what returning by value does. It copies the result of the expression in the return statement into a return value.
localVar must not be generated on the stack. If a register is available it could be used also.
If it was in fact created on the stack then the value is copied to a register anyway on returning.
Because of the return type of your function: int myFunc(). It allows you to pass back an int value. The variable localVar is indeed out of scope in main(), but localVar is not being used there, y is, and when used as y = myFunc(), it accepts the int value returned.