Destructor and garbagecollector

  • Thread starter Thread starter Peter Hemmingsen
  • Start date Start date
P

Peter Hemmingsen

Hi,

I have written a dotnet class that in its constructor consumes a license
from a central license pool. In the destructor it free the license again.
But since I don't know when the destructor is called (that is up to the
garbage collector) the object (and hence the application) consume a license
although it is not in use any more.

I could of course write a specific "logoff" method to run the specific part
of the destructor code that frees the license, but then I have to deal with
an object that is "de-initialized" and therefore not usable.

Is there any other place to implement destructor code that are always called
immediately when the object is deleted?

Peter
 
Hi,

Check out the Dispose pattern (Google for "Dispose pattern MSDN" without the
quotes and you should find it). There is no way to get the same behaviour as
C++ stack objects, but Dispose is the recognized way of getting stuff to
release resources in a timely fashion.

Steve
 
Hi Steve,

Thanks for your reply. I guess that is the way I have to do it. But then I
need to add code to all the method (and properties) to check if the Dispose
has been called,- and if so throw an exception. The nice thing about the
destructor is that the object simply no longer exist so the methods can not
be called.

Peter
 
Hi,

The Dispose pattern helps you cope with that - it should be safe to call it
multiple times without a problem. As long as you know when you're finished
with something it should work. Incidentally, having something just suddenly
not be there isn't a great way to be done with it - if you have something
storing pointers to objects and the things pointed to aren't there any more,
you'll get null pointer exceptions. It sounds like you might want to use
something similar to a weak pointer (or weak reference, the .NET stuff calls
it). I've never used them in MC++ but the gist is that weak pointers will
not keep an object alive as far as the GC is concerned, but if the object is
still alive and you try to use it from the weak pointer it will create a
strong pointer for you to use. If you're using unmanaged C++ the Boost
library has a great imlpementation; otherwise check out the .NET docs. for
'weak references'.

Additionally, you may want to consider some kind of messaging system to let
the container know that something it should be storing doesn't exist any
more. Maybe you can post simplified code here so I can get a better idea of
what you're doing?

Steve
 
Hi Steve,

Thanks a lot for your reply.
My constructor connects to a server and consume a license. If this succeed I
now have a "connection" object with methods to get work done on the server
(e.g: search for something on the server by calling ConObj.Find(....)).

If the user of my library (that is the programmer) calls Dispose (release
the license and disconnect from the server) and then later try to call the
Find method it will fail (somehow) because the connection to the server is
gone. It would be nice if all methods would throw the same
"ObjectHasBeenDisposed" exception but that would require me to make a check
in all methods. Alternatively the programmer must be prepared for a number
of different exception if he keeps working on an object that has been
disposed.

Again thanks.

Peter
 
Hi,

It sounds as though instead of just keeping the connection as a member state
you could do with having it wrapped somewhere, with an accessor function.
The accessor function can then check whether the connection exists.
Something like what's below (excuse any errors, I'm doing this in between
links). This way, you need to put your exception call in one place and it
also breaks things up a bit. Really, if the user of your lib calls Dispose()
it implies they've got no use for it. Using a Disposed object is not a good
thing to do. Instead, you may just want to have Connect and Disconnect
functions. What's the context for all this?

__gc class ConnectionWrapper
{
void DisposeConnection()
{
conn->Dispose();
conn = 0;
}

void CreateConnection()
{
....
}

Connection *GetConnection()
{
if ( conn )
{
return conn;
}
else
{
throw HorribleException; // Or CreateConnection, whichever
you want to do.
}
}
private:
Connection *conn;
}
 
Hi Steve,

We are developing a client/server based document management system (first
version released back in 1988) so the server code and the client library
(using RPC) is developed in C. We have know wrapped the client C library
into MC++ and then clients can be written in C#.

In fact I already have a GetConnection method. It is static and provides a
singleton scheme for the connection object. However I can't avoid the
programmer to write something like this:

SEConnection con = SEConnection.GetConnection();
....
con.Dispose();

con.Find(...); // Horrible error

but I guess that is up to the programmer never to use a disposed object.

Peter
 
Hi,

Yeah, the programmer should spot that (and more importantly it will be very
obvious at first test that something's wrong). But using C++ stack objects
wouldn't help this - you'd get

{
SEConnection con = SEConnection.GetConnection();
...
}
con.Find();

and get a compiler error. This might be slightly better than the runtime
error you'd get using Dispose but it's not ideal. Incidentally, you can
still scope the calls so the con.Find() line won't compile. Dispose is used
as a way of releasing resources in a timely fashion rather than waiting for
the garbage collector.

Steve
 
Thanks for all you comments.

One last question:

What do I gain from deriving from IDisposable? (As apposed to just making a
public Dispose method)

Peter
 
Hi,

Have a look at this sample MC++ code:

public __gc class MyTable : public DataTable, public IDisposable {
public:
MyTable() {GC::ReRegisterForFinalize(this); m_p=malloc(1000);};
~MyTable() {GC::SuppressFinalize(this);Dispose();};
virtual void Dispose() {free(m_p);};

private:
void* m_p;
};

First of all the GC::ReRegisterForFinalize in the constructor is required
because the DataTable implementation will always have GC::SuppressFinalize
meaning that the MyTable destructor by default will never be called.

The above code can't compiler because the DataTable has a derived Dispose
method that are marked as sealed.

If I instead of naming my method Dispose name it CleanUp then the user of
MyTable could still just call Dispose (not realizing that there is a CleanUp
method) and then the MyTable unmanaged resources are not released.

Any suggestion?

Peter
 
The Dispose() method in MarshalByValueComponent should call Dispose(
Boolean ), passing in true. The version with the argument is virtual, so can
be overriden. The docs for MarshalByValueComponent say:

"Notes to Inheritors: When you inherit from this class, you can override
the Dispose, Site, and the GetService methods."

You probably don't want to separately implement IDisposable (I'm surprised
it lets you do that at all) - MarshalByValueComponent implements it, so you
just want to override its Dispose function.

Steve
 
No probs, these newsgroups are a great resource, and one of the reasons we
develop PC versions of our stuff before OS X releases - the Mac's a great
platform but it's so hard finding any developer resources. Good luck with
things!

Steve
 
Back
Top