Derelict SFML destructor crashes
Mike Parker
aldacron at gmail.com
Mon Dec 17 05:51:45 PST 2012
On Monday, 17 December 2012 at 10:39:56 UTC, Jeremy DeHaan wrote:
>>
> I tried putting destroy in the destructor like the code I
> wrote. Like I said, it gave me no memory errors, but I don't
> actually know if it even does anything. I honestly think that
> it is weird to not be able to rely on destructors like this. To
> me, it makes sense that the destructor would be a part of the
> garbage collection, but again I don't have any sort of
> experience with memory management. I find it kind of silly to
> have something like a destructor built into a language, but it
> not being reliable and more or less something to be completely
> ignored altogether. I do understand that in most cases this can
> be so, as the GC will free up the memory itself, but in some
> cases it could be useful to know your destructor will free up
> the resources the GC can't.
I've not yet used destroy and am not familiar with everything it
does, but I do know that it isn't going to help you with an
sfImage because the memory for that was not allocated by the GC.
What I do know about destroy is that if you do want some control
over when destructors are called then destroy is what you would
use to do it. destroy(myClassInstance) will call the destructor
of the object. But, it will not deallocate the object's memory.
Unlike the deprecated delete, object destruction and memory
deallocation have been decoupled with destroy.
However, if you are going to take this route, then you have to
make sure that every object which releases resources in its
destructor is manually destroyed. This is no different than what
I do with my term() methods. But I like my approach better. All
objects have destructors, but only those that need to release
resources have a term() method, so I'm less likely to make silly
mistakes at 3 am after several hours of coding.
At any rate, unreliable destructors are usually what you get when
you are using a GCed language (or none at all, like in Java).
They're not completely useless, though.
>
>
>> The scope(exit) in the main method ensures that this
>> termination chain is run every time the app exits regardless
>> of the reason
>
> This is good to know. I read about this, but haven't used it
> yet. Wouldn't the destructors get called at this point?
No. Whatever code you have in the scope block gets called.
import std.stdio;
scope(exit) writeln("Foo");
scope(success)
{
writeln("Bar");
writeln("Baz");
}
All that's happening here is that the code you've included in the
scope blocks will be called. The first block will execute no
matter how the scope exits. The second block will only execute
when the scope exits normally (and not due to an exception). The
output will be:
Bar
Baz
Foo
Because the scope blocks are always executed in the reverse order
they are encountered. scope(failure) will run when exiting due to
an error.
So with these statements, there's nothing going on under the hood
to call destructors or release memory.
>
>
>
> Also, what about something like this?
>
> void main(string[] args)
> {
> {
> init();
> gameLoop();
> }<-Wouldn't the destructors get called here? Or would the GC
> run first?
> }<-And what would happen here? Would GC be run again after the
> scope is left?
The main method in your D module is not the program entry point.
The real entry point is in DRuntime. See the dmain2.d module in
the Druntime source. At line 367 (in the current master) you'll
see the entry point.
https://github.com/D-Programming-Language/druntime/blob/master/src/rt/dmain2.d#L367
extern (C) int main(int argc, char **argv)
{
return _d_run_main(argc, argv, &_Dmain);
}
Looking in _d_run_main, you'll see a bit of platform-specific set
up code for each platform, then a series of inner functions. At
the bottom of _d_run_main is this line:
tryExec(&runAll);
runAll is an innder function inside _d_run_main, defined just
above this tryExec call. It looks like so:
void runAll()
{
gc_init();
initStaticDataGC();
rt_moduleCtor();
rt_moduleTlsCtor();
if (runModuleUnitTests())
tryExec(&runMain);
else
result = EXIT_FAILURE;
rt_moduleTlsDtor();
thread_joinAll();
rt_moduleDtor();
gc_term();
}
It initializes the GC, then calls the module constructors, then
runs unit tests, then calls your main function. When your main
function returns, module destructors are run, then gc_term is
called to finalize the GC. It is here that any objects still
hanging around in the GC that have not be destructed will have
their destructors called and then all the memory is released.
>
>
> I am just trying to understand the language better. So far it
> seems that the only way to prevent memory leaks when memory is
> being allocated outside of D is to manually delete those
> objects yourself and to not rely on the destructors. I will
> make sure this happens in the future!
It's not the only way, but it's the easiest way.
>
> Sorry if I say silly things. I am but a young programmer trying
> to gain knowledge!
More information about the Digitalmars-d-learn
mailing list