Stupid scope destruction question
monarch_dodra
monarchdodra at gmail.com
Thu Sep 20 04:35:56 PDT 2012
On Thursday, 20 September 2012 at 09:31:45 UTC, Denis
Shelomovskij wrote:
> 20.09.2012 13:27, Denis Shelomovskij пишет:
>> Is there any guaranties that `ScopeTemp` will not be destroyed
>> before
>> `f` call because it isn't used?
>> ---
>> struct ScopeTemp
>> {
>> ...
>> // allocates value
>> this(...) { ... }
>>
>> @property void* value() { ... }
>>
>> // destroys value
>> ~this() { ... }
>> }
>>
>> void f(void* ptr) { ... }
>>
>> void main()
>> {
>> f(ScopeTemp(...).value);
>> }
>> ---
>> According to http://dlang.org/struct.html#StructDestructor
>> "Destructors are called when an object goes out of scope."
>> So I understand it as "it will not be destroyed before scope
>> exit even
>> if not used". Is it correct?
>>
>> So the question is if `ScopeTemp`'s scope is `main` scope, not
>> some
>> possibly generated "temp scope" (don't now what documentation
>> statements
>> prohibit compiler from doing so).
>>
>>
>> Working code:
>> ---
>> import std.exception;
>> import std.c.stdlib;
>>
>> struct ScopeTemp
>> {
>> private int* p;
>> // allocates value
>> this(int i)
>> in { assert(i); }
>> body { *(p = cast(int*) enforce(malloc(int.sizeof))) = i; }
>>
>> @disable this(this);
>>
>> @property int* value() { return p; }
>>
>> // destroys value
>> ~this() { *p = 0; p = null; /*free(p);*/ }
>> }
>>
>> void f(int* ptr)
>> {
>> assert(*ptr == 1);
>> }
>>
>> void main()
>> {
>> f(ScopeTemp(1).value);
>> }
>> ---
>
> Wow, this `main` works fine too:
> ---
> // same ScopeTemp definition as above
>
> int* gptr;
>
> void f(int* ptr)
> {
> assert(*ptr == 1);
> gptr = ptr;
> }
>
> void g()
> {
> assert(*gptr == 0);
> }
>
> void main()
> {
> f(ScopeTemp(1).value);
> // Here `ScopeTemp` value is already destroyed
> g();
> }
> ---
>
> So `ScopeTemp`'s scope definitely isn't a `main` scope. So the
> question: what do we know about this "temp scope"?
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."
The two catches are:
*"The implementation is allowed to elide the copy for pass by
value, even if it has visible side effects, and construct
directly into the function's stack."
*"If the function is able to use "(Named) Return Value
Optimization" "(N)RVA" (invented by Walter himself), the returned
value's destruction will not be observable (as it won't happen)."
Try running this:
C++
----
#include <iostream>
struct S
{
int i;
S(int i) : i(i) {::std::cout << "C:" << i << ::std::endl;}
S(const S&){::std::cout << "CC:" << i << ::std::endl;}
~S(){::std::cout << "D~:" << i << ::std::endl;}
};
S foo(S)
{
::std::cout << "foo(S)" << ::std::endl;
return S(2);
}
S foo(int)
{
::std::cout << "foo(int)" << ::std::endl;
return S(6);
}
int main()
{
foo(S(1));
foo(S(5).i);
}
----
C:1
foo(S)
C:2
D~:2
D~:1
C:5
foo(int)
C:6
D~:6
D~:5
----
D:
----
import std.stdio;
struct S
{
int i;
this(int j){i = j;writeln("C",i);}
this(this){writeln("PB",i);}
~this(){writeln("D~",i);}
};
S foo(S)
{
writeln("foo(S)");
return S(2);
}
S foo(int)
{
writeln("foo(int)");
return S(6);
}
void main()
{
S a = foo(S(1));
S a = foo(S(5).i);
}
----
C1
foo(S)
C2
D~1
D~2
C5
foo(int)
C6
D~6
D~5
----
I haven't seen any difference between C++ and D, including the
argument pass by value elision, as well as (N)RVA
More information about the Digitalmars-d-learn
mailing list