scope(~this)

Inquie via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Mar 13 07:28:01 PDT 2017


On Monday, 13 March 2017 at 05:18:18 UTC, Nicholas Wilson wrote:
> On Sunday, 12 March 2017 at 21:38:44 UTC, Inquie wrote:
>> Is there any easy way to create a scope for termination of the 
>> object?
>>
>> I have a template method that takes a type and allocates and 
>> deallocates based on that type.
>>
>> class bar
>> {
>>    void foo(T)()
>>    {
>>       T x;
>>       alloc(x);
>>       scope(~this) dealloc(x); // hypothetical that wraps the 
>> statement in a lambda and deallocates in the destructor
>>
>>       ... x must stay allocated until class instance 
>> termination(has to do with COM, can't release it in foo)
>>    }
>>
>> }
>>
>> Now, x cannot be a field because T is unknown(i suppose I 
>> could use object, void*, etc, but...).
>>
>
> If it is COM then you should use IUnknown (the COM root 
> interface),or if you are expecting multiple calls to foo, an 
> array of IUnknown. I think the GC will clean up completely for 
> you in either case and call release(?) on the member(s).
>
> Also as it is COM you probably don't need to template it, just 
> choose T to be the most recent ancestor of all (old) T's you 
> would be expecting foo to be instantiated with (e.g. IUnknown 
> if you expect any COM object.

Sorry, but that is missing the point! First, it isn't that 
simple. I do not think the GC will call release as the GC has no 
idea of COM nor the interfaces. While it might be safe not to 
release them and let the OS deal with it, this is not standard. 
The template is to not part of COM but required to dynamically 
instantiate the COM interface that is not supplied(using 
GetIDsOfNames).

So, the way it work is, I have a function that takes an interface 
which specifies the dynamic COM functions. Using 
GetIDsOfNames(since that seems to be the only way) gets the 
function pointers to these functions in which I build up a new 
object representing that interface. The problem is, One must use 
CoCreateInterface to create the COM object to use 
GetIDsOfNames(neither of which depends on the interface). But 
CoCreateInterface returns the interface with the Release function 
as a member and this function must be called later(at terminate 
of the overall class handling all this stuff).

But since I have to create a variable with the interface to get 
the methods and to pass to CoCreateInstance, and eventually use 
it to call Release, I can't discard the variable at the end of 
the function.

Basically the interface's lifetime must exist for the entirety of 
the containing object. Normally one would use the constructor and 
class fields to manage this, but it is impossible here because 
the actual interfaces are unknown at compile time(they are 
extracted from an idl by this class).

The only thing I could do is keep an array of all these IUnknown 
interfaces(sorta using the above technique), since IUnknown has 
the Release function in it, basically using your suggestion or 
what I originally said is a feasible solution.

But this pollutes the class name space unnecessarily(I know it is 
just an array, but ultimately should be unnecessary).

Rather, if I could simply use a

scope(~this) or some other mechanism, everything will be 
automatically taken care of.

scope(~this) X.Release();

would realize that X, the local variable in the function, will be 
used and the GC will not free it just like delegates do(although 
it would need to be copied to the heap so future function calls 
won't corrupt the value when used on the stack, or, alternatively 
I could malloc it in the function instead).

Then, on destruction, the scope is executed. X still exists.

In this case, it's 1 line of code rather than about 5(a class 
field array, an append, and calling release on all appends in the 
destructor). It's very clear and very precise.

It's very similar to scope(exit) for function but for 
classes(since classes can "exit" too).

It may be better to call it

scope(this)

which is more clear(when the scope of the object instance is 
over, then "execute" what follows).

I think this feature would actually be quite useful. Instead of 
handling many things in the destructor, we can handle them on 
site. e.g., any class resources that are allocated could then 
have a scope(this) right after allocation to deallocate them 
instead of having to push it in the the destructor which 
separates the code visually and programmatically. The same 
argument which is used to make scope(exit) useful, but on a 
higher level... Which, if we follow it, we should then also have 
scope(application) or something for application level scope.


















More information about the Digitalmars-d-learn mailing list