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