Jump to page: 1 2
Thread overview
Releasing resources
Jan 30, 2006
rlpt
Jan 31, 2006
Hasan Aljudy
Jan 31, 2006
Mike Parker
Jan 31, 2006
James Dunne
Jan 30, 2006
clayasaurus
Jan 31, 2006
Stewart Gordon
Jan 31, 2006
Stewart Gordon
Jan 31, 2006
Derek Parnell
Feb 01, 2006
Carlos Santander
Feb 01, 2006
Stewart Gordon
Feb 01, 2006
Sean Kelly
January 30, 2006
In a language binding to a C library that I'm writing, the Context class need to allocate some resources that should be deallocated when finish using it. Since the destructors aren't guaranteed to be called on classes... How can I be sure the class is releasing all it's resources?

Here's an example of what I'm looking to archieve:

| class Example
| {
|     Context ctx = new Context();
|
|     void save()
|     {
|         ctx.save(cast(void*)this, this.sizeof);
|     }
| }
|
| void main()
| {
|     Example e = new Example();
|     e.save();
|     // e.ctx's destructor should be called here.
| }

Thanks


January 30, 2006
<rlpt@pathlink.com> wrote in message news:drl64t$2ulv$1@digitaldaemon.com...
> In a language binding to a C library that I'm writing, the Context class
> need to
> allocate some resources that should be deallocated when finish using it.
> Since
> the destructors aren't guaranteed to be called on classes... How can I be
> sure
> the class is releasing all it's resources?

I usually keep a list of all instances in existence, and delete them all in a static dtor:

class Example
{
    Context ctx;  // You can't new a class member out here

    this()
    {
        ctx = new Context();
        examples[this] = this;
    }

    ~this()
    {
        delete ctx;
        examples.remove(this);
    }

    protected static Example[Example] examples;

    static ~this()
    {
        foreach(Example e; examples)
            delete e;
    }

    void save()
    {
        ctx.save(cast(void*)this, this.sizeof);
    }
}


Of course, you may want to move this into the Context class instead (keep a list of Contexts and delete them all at the end, as it's really Context which holds the resources and not Example).


It really is irritating that dtors are not guaranteed to be called, isn't it?  Poor Walter doesn't seem to understand that there are resources other than vanilla memory that need to be deallocated.  Seems kind of pointless to even have dtors then, if they can't be expected to be the opposite of a ctor.


January 30, 2006
Does the following work?

auto Example e = new Example();
e.save();

// dtor is called when e is out of scope

rlpt@pathlink.com wrote:
> In a language binding to a C library that I'm writing, the Context class need to
> allocate some resources that should be deallocated when finish using it. Since
> the destructors aren't guaranteed to be called on classes... How can I be sure
> the class is releasing all it's resources? 
> 
> Here's an example of what I'm looking to archieve:
> 
> | class Example
> | {
> |     Context ctx = new Context();
> | |     void save()
> |     {
> |         ctx.save(cast(void*)this, this.sizeof);
> |     }
> | }
> | | void main()
> | {
> |     Example e = new Example();
> |     e.save();
> |     // e.ctx's destructor should be called here.
> | }
> 
> Thanks
> 
> 



January 31, 2006
Jarrett Billingsley wrote:
> <rlpt@pathlink.com> wrote in message news:drl64t$2ulv$1@digitaldaemon.com...
> 
>>In a language binding to a C library that I'm writing, the Context class need to
>>allocate some resources that should be deallocated when finish using it. Since
>>the destructors aren't guaranteed to be called on classes... How can I be sure
>>the class is releasing all it's resources?
> 
> 
> I usually keep a list of all instances in existence, and delete them all in a static dtor:
> 
> class Example
> {
>     Context ctx;  // You can't new a class member out here
> 
>     this()
>     {
>         ctx = new Context();
>         examples[this] = this;
>     }
> 
>     ~this()
>     {
>         delete ctx;
>         examples.remove(this);
>     }
> 
>     protected static Example[Example] examples;
> 
>     static ~this()
>     {
>         foreach(Example e; examples)
>             delete e;
>     }
> 
>     void save()
>     {
>         ctx.save(cast(void*)this, this.sizeof);
>     }
> }
> 
> 
> Of course, you may want to move this into the Context class instead (keep a list of Contexts and delete them all at the end, as it's really Context which holds the resources and not Example).
> 
> 
> It really is irritating that dtors are not guaranteed to be called, isn't it?  Poor Walter doesn't seem to understand that there are resources other than vanilla memory that need to be deallocated.  Seems kind of pointless to even have dtors then, if they can't be expected to be the opposite of a ctor. 
> 
> 

Last time I checked, D had RAII (ironically, it's now suggested in another thread to rename RAII to RR, meaning "resource release", because that's exactly what it is).

it's like this:
//new scope
{
   auto Context c = new Context( /* whatever */ );
   // .. code ..
}  // scope finished, c is deleted and the destructor is called

This should do it, unless I'm missing something!!
January 31, 2006
Hasan Aljudy wrote:
> 
> it's like this:
> //new scope
> {
>    auto Context c = new Context( /* whatever */ );
>    // .. code ..
> }  // scope finished, c is deleted and the destructor is called
> 
> This should do it, unless I'm missing something!!

That doesn't work for objects that need to be valid through the life of the program or across multiple method calls, unless of course you declare them in main(). Then that severely limits your design. Consider a global Database context.

I'm content to use init & shutdown methods for objects which allocate system resources and need to release them. No biggie.
January 31, 2006
rlpt@pathlink.com wrote:
> In a language binding to a C library that I'm writing, the Context class need to
> allocate some resources that should be deallocated when finish using it. Since
> the destructors aren't guaranteed to be called on classes... How can I be sure
> the class is releasing all it's resources? 
<snip>

Call gc_term() immediately before your program exits.

Stewart.

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/M d- s:- C++@ a->--- UB@ P+ L E@ W++@ N+++ o K-@ w++@ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y
------END GEEK CODE BLOCK------

My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
January 31, 2006
"Stewart Gordon" <smjg_1998@yahoo.com> wrote in message news:drnk3s$30po$1@digitaldaemon.com...
> rlpt@pathlink.com wrote:
> Call gc_term() immediately before your program exits.

gc_term() gets called by dmain() anyway, and it doesn't call dtors.  So if you have resources held in objects which are anything but memory allocated by new (like OS handles or something) and which need to be deallocated in a special way, gc_term() won't get that done.


January 31, 2006
Jarrett Billingsley wrote:
> "Stewart Gordon" <smjg_1998@yahoo.com> wrote in message news:drnk3s$30po$1@digitaldaemon.com...
>> rlpt@pathlink.com wrote:
>> Call gc_term() immediately before your program exits.
> 
> gc_term() gets called by dmain() anyway,

It didn't use to.

http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/3569

> and it doesn't call dtors.
<snip>

When did this change?  It isn't in the change log at all.  And

http://www.digitalmars.com/d/windows.html

still states that it does.  And I can't imagine why Walter would have changed the semantics of gc_term so that it doesn't do what some of us are rightly relying on it to do, let alone not bothered telling us.

Stewart.

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/M d- s:- C++@ a->--- UB@ P+ L E@ W++@ N+++ o K-@ w++@ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y
------END GEEK CODE BLOCK------

My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
January 31, 2006
Mike Parker wrote:
> Hasan Aljudy wrote:
> 
>>
>> it's like this:
>> //new scope
>> {
>>    auto Context c = new Context( /* whatever */ );
>>    // .. code ..
>> }  // scope finished, c is deleted and the destructor is called
>>
>> This should do it, unless I'm missing something!!
> 
> 
> That doesn't work for objects that need to be valid through the life of the program or across multiple method calls, unless of course you declare them in main(). Then that severely limits your design. Consider a global Database context.
> 
> I'm content to use init & shutdown methods for objects which allocate system resources and need to release them. No biggie.

I ran across this exact same problem.  Turns out I went adventurous and modified phobos to include a "guaranteed" destruction call, even if a segfault occurred.  This was for Linux only, since I knew how to do it there, but the concept is the same for Windows.

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/MU/S d-pu s:+ a-->? C++++$ UL+++ P--- L+++ !E W-- N++ o? K? w--- O M--@ V? PS PE Y+ PGP- t+ 5 X+ !R tv-->!tv b- DI++(+) D++ G e++>e h>--->++ r+++ y+++
------END GEEK CODE BLOCK------

James Dunne
January 31, 2006
"Stewart Gordon" <smjg_1998@yahoo.com> wrote in message news:dro1g2$o3n$1@digitaldaemon.com...
> It didn't use to.

You post there talks about WinMain, which replaces dmain() if you're writing a Windows app.  But check it out - dmd/src/phobos/internal/dmain2.d.  Right under the "result = main(args)" line, the module dtors and gc_term() get called.  I'm kind of surprised that it's in the try block and not after the catch, though.  Maybe that's a bug?

> When did this change?  It isn't in the change log at all.  And
>
> http://www.digitalmars.com/d/windows.html
>
> still states that it does.  And I can't imagine why Walter would have changed the semantics of gc_term so that it doesn't do what some of us are rightly relying on it to do, let alone not bothered telling us.

That's news to me.  gc_term() does, in fact, seem to work for this little test prog (I had to do the WinMain version since I don't feel like changing dmain and recompiling phobos.. what a pain!):

import std.stdio;
import std.c.windows.windows;

class A
{
 this()
 {
  writefln("A ctor");
 }

 ~this()
 {
  writefln("A dtor");
 }
}

int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpszCmdLine, INT nCmdShow)
{
 A a = new A;
 return 0;
}

// ------------------------------------------------------------------------------------------------

extern(C) void gc_init();
extern(C) void gc_term();
extern(C) void _minit();
extern(C) void _moduleCtor();
extern(C) void _moduleDtor();
extern(C) void _moduleUnitTests();

extern(Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, INT nCmdShow)
{
 int result;
 gc_init();
 _minit();

 try
 {
  _moduleCtor();
  _moduleUnitTests();
   result = myWinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow);
 }
 catch(Object o)
 {
  MessageBoxA(null,o.toString(),"Error",MB_OK | MB_ICONEXCLAMATION);
  result = 0;
 }

 _moduleDtor();

 writefln("gc_term()");
 gc_term();
 writefln("gc_term() end");

 return result;
}

This prints

A ctor
gc_term()
A dtor
gc_term() end

However, in one of my programs, I must delete all instances of a class manually or else their dtors don't get called.. I'll look into why that's happening.


« First   ‹ Prev
1 2