Which happens first: destructors or return?

J

jl_post

Hi,

Recently I was wondering something:

If a function is returned from (returning a value), does the value
get returned as-is before any destructors are called? For example, if
I have a function like:

int f()
{
int i = 7;
Blah blah(i); // modifies i in destructor
return i;
}

does 7 get returned, or does i's modified value get returned?

In case a complete program is needed for clarification, here's one:


#include <iostream>

class EndOfScopeDoubler // modifies the integer in its destructor
{
public:
EndOfScopeDoubler(int & _value) : value(_value) { }
~EndOfScopeDoubler() { value *= 2; }
private:
int & value;
};


int i = 7; // global variable

int f()
{
EndOfScopeDoubler blah(i);
return i;
}

int main(int argc, char ** argv)
{
std::cout << "i (before) = " << i << std::endl;
std::cout << "f() returns " << f() << std::endl;
std::cout << "i (after) = " << i << std::endl;

return 0;
}

i (before) should be 7. i (after) should be 14. But what should f
() return? It could return 7 or 14, depending on whether the
EndOfScopeDoubler destructor fires off before the return statement or
not.

When I run this program, I see:

i (before) = 7
f() returns 7
i (after) = 14

The fact that i ended up as 14 tells me that the EndOfScopeDoubler
destructor did fire off, but the fact that f() returned 7 tells me
that the value 7 got returned before the destructor got a chance to
modify it.

(Just so you know, if I surround the line "EndOfScopeDoubler blah
(i);" with curly braces, f() will return 14.)

My question is: Is having the return value returned before the
destructor(s) fire off defined behavior? Sure, my compiler happens to
think so, but I'm wondering if this is valid C++ behavior (or simply
undefined).

Thanks.

-- Jean-Luc
 
B

Balog Pal

If a function is returned from (returning a value), does the value
get returned as-is before any destructors are called? For example, if
I have a function like:

int f()
{
int i = 7;
Blah blah(i); // modifies i in destructor
return i;
}

does 7 get returned, or does i's modified value get returned?

The expression i is evaluated and found at value 7. So that is returned.
Destructors are called after that.
My question is: Is having the return value returned before the
destructor(s) fire off defined behavior? Sure, my compiler happens to
think so, but I'm wondering if this is valid C++ behavior (or simply
undefined).

I see nothing in the standard that would make it undefined.
 
D

Daniel Pitts

Balog said:
The expression i is evaluated and found at value 7. So that is returned.
Destructors are called after that.


I see nothing in the standard that would make it undefined.
I'm curious, is there something in the standard that guarantees that "i"
isn't deallocated or destroyed before blah? I could see a situation,
(particularly if i weren't an int) where i was destroyed before blah,
causing UB in blah having a reference to it.
 
M

MiB

On Jan 20, 6:25 pm, Daniel Pitts
I'm curious, is there something in the standard that guarantees that "i"
isn't deallocated or destroyed before blah?  I could see a situation,
(particularly if i weren't an int) where i was destroyed before blah,
causing UB in blah having a reference to it.

The "return" mechanism of C++ works by value. This means, not the
object i is returned to the caller as such. Instead, a temporary int
is created, i is interpreted as an expression (its value) is copied
into it and handed back. This becomes more intuitive is you consider
the statement "return i + 1;" instead --- i+1 is not handled
structurally different. Depending on compiler and machine architecture
the temp may be a reserved space on the caller's CPU stack frame, or a
CPU register dedicated for this purpose. Optimizing compilers may even
detect situations like "int x = f();" and use "x" directly to store
the 'temporary' value, skipping unnecessary copying.

Anyway, the temp container is a separate entity from "i" and the
destruction or any assumed later manipulation of "i" in between the
"return" and the closing brace does not affect it.

Maybe you got confused by Java or C# semantics, where class objects
actually are returned by reference - for these, no destructor is
called because the garbage collector does not see them as
unreferenced.

MiB.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,152
Members
46,698
Latest member
LydiaHalle

Latest Threads

Top