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.
















Reply via email to