Stupid scope destruction question

monarch_dodra monarchdodra at gmail.com
Mon Sep 24 12:46:45 PDT 2012


On Monday, 24 September 2012 at 17:49:22 UTC, Ali Çehreli wrote:
> On 09/24/2012 12:49 AM, monarch_dodra wrote:
> > On Monday, 24 September 2012 at 07:25:28 UTC, Denis
> Shelomovskij wrote:
> >> 20.09.2012 15:35, monarch_dodra пишет:
> >>>
> >>> AFAIK, if the rules are the same in C++ (which they
> probably are), then:
> >>> "Any object constructed during argument passing will remain
> valid for
> >>> the duration of the call. It will go out of scope once the
> function has
> >>> finished returning, and after the return value has itself
> gone out of
> >>> scope and been destroyed."
>
> That sounds like you are saying that the temporary S() is 
> destroyed after 'r' below:
>
>     // C++ code
>     R r = foo(S());
>
> > How is my statement incorrect? The "function call" itself
> doesn't change
> > anything sure, since it is more generally a "full
> expression": The
> > return value itself is created *during* that full expression,
> but after
> > the creation of the arguments. Last in, first out, it is
> destroyed
> > before the passed in arguments.
>
> That is not correct. The temporary S() is destroyed at the end 
> of the assignment expression (at the semicolon), while 'r' will 
> live until the end of the current scope.
>
> Ali

Ah... but see, "s" is *not* the temporary returned value.

It is a normal stack variable to which the the return value is 
copied. Also, as I said, in this situation, the compiler will 
elide the return completely by constructing the returned value 
directly into s, so you won't see the destroyer.

Try this though:
--------
void main()
{
   S s;
   foo(S(1));
}
--------
D:        C++
----      ----
C0        C:0
C1        C:1
foo(S)    foo(S)
C2        C:2
D~1       D~:2
D~2       D~:1
D~0       D~:0
----      ----


As you can see, three destructors. It would appear that D, 
contrary to C++, actually destroys the return value before the 
passed in arguments. Interesting. A valid behavior like any other 
I guess, but doesn't change much. I'll admit I was wrong 
regarding that (regarding D), but it stays right for C++ :p

Not your example you ask? HERE is the *money* example:
--------
void main()
{
   S s;
   s = foo(S(1));
}
--------
D:        C++
----      ----
C0        C:0
C1        C:1
foo(S)    foo(S)
C2        C:2
D~1       D~:2
D~0       D~:1
D~2       D~:2
----      ----

Again 3 destroyers. Again, C++, again works as I said.

Regarding D, WTF is D~0 ? That is D's "return value move" into 
action! First time I observe it myself! Exciting!

* First, the passed in argument is destroyed: D~1.
* Then it gets interesting:
* D first calls a destroyer on s (but doesn't actually remove it 
from the stack): D~0.
* Then D does a memcpy from the returned value, onto s (the move).
* Finally, the actual return value is then removed from the 
stack, but no destructor ever called on it.
* Finally, at the end of the program, s is destroyed (D~2).

Neat-o!


More information about the Digitalmars-d-learn mailing list