www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Derelict SFML destructor crashes

reply "Nekroze" <nekroze eturnilnetwork.com> writes:
I am trying to do some wrapping of the CSFML derelict bindings to 
classes however when i use the CSFML methods to destroy the 
objects it causes a crash.

I have made a post in the SFML>D forum because they have syntax 
highlighting for D so this kind of post looks nicer but the link 
is here:

http://en.sfml-dev.org/forums/index.php?topic=10005.0

There is a minimal code example there and a better explanation.

Can anyone help me with why this is happening?
Dec 16 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Sunday, 16 December 2012 at 14:42:57 UTC, Nekroze wrote:
 I am trying to do some wrapping of the CSFML derelict bindings 
 to classes however when i use the CSFML methods to destroy the 
 objects it causes a crash.

 I have made a post in the SFML>D forum because they have syntax 
 highlighting for D so this kind of post looks nicer but the 
 link is here:

 http://en.sfml-dev.org/forums/index.php?topic=10005.0

 There is a minimal code example there and a better explanation.

 Can anyone help me with why this is happening?
Why would you call a destroy() on a this object inside ~this()? And accessing allocated by GC objects inside destructor is not safe, because they may be collected before running the destructor.
Dec 16 2012
parent reply "Nekroze" <nekroze eturnilnetwork.com> writes:
On Sunday, 16 December 2012 at 14:59:32 UTC, Maxim Fomin wrote:
 On Sunday, 16 December 2012 at 14:42:57 UTC, Nekroze wrote:
 I am trying to do some wrapping of the CSFML derelict bindings 
 to classes however when i use the CSFML methods to destroy the 
 objects it causes a crash.

 I have made a post in the SFML>D forum because they have 
 syntax highlighting for D so this kind of post looks nicer but 
 the link is here:

 http://en.sfml-dev.org/forums/index.php?topic=10005.0

 There is a minimal code example there and a better explanation.

 Can anyone help me with why this is happening?
Why would you call a destroy() on a this object inside ~this()? And accessing allocated by GC objects inside destructor is not safe, because they may be collected before running the destructor.
I am sorry if i am being dim but i thought that the sfml objects are not GC objects so it will exist forever until i call its destroy function so why cant this be done in the destructor? Unless you mean the pointer is being destroyed before the destructor is being called?
Dec 16 2012
next sibling parent "Nekroze" <nekroze eturnilnetwork.com> writes:
On Sunday, 16 December 2012 at 15:21:46 UTC, Nekroze wrote:
 On Sunday, 16 December 2012 at 14:59:32 UTC, Maxim Fomin wrote:
 On Sunday, 16 December 2012 at 14:42:57 UTC, Nekroze wrote:
 I am trying to do some wrapping of the CSFML derelict 
 bindings to classes however when i use the CSFML methods to 
 destroy the objects it causes a crash.

 I have made a post in the SFML>D forum because they have 
 syntax highlighting for D so this kind of post looks nicer 
 but the link is here:

 http://en.sfml-dev.org/forums/index.php?topic=10005.0

 There is a minimal code example there and a better 
 explanation.

 Can anyone help me with why this is happening?
Why would you call a destroy() on a this object inside ~this()? And accessing allocated by GC objects inside destructor is not safe, because they may be collected before running the destructor.
I am sorry if i am being dim but i thought that the sfml objects are not GC objects so it will exist forever until i call its destroy function so why cant this be done in the destructor? Unless you mean the pointer is being destroyed before the destructor is being called?
To me it makes sense to use the sfml objects destroy function when the my object gets destroyed regardless of when it happens. It cant be that i have to have a separate destroy method for my class that i must manually use each time. kind of kills the point of having a GC then doesn't it? Like i said sorry if i am being dim that just makes sense to me.
Dec 16 2012
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Sunday, 16 December 2012 at 15:21:46 UTC, Nekroze wrote:
 On Sunday, 16 December 2012 at 14:59:32 UTC, Maxim Fomin wrote:
 On Sunday, 16 December 2012 at 14:42:57 UTC, Nekroze wrote:
 I am trying to do some wrapping of the CSFML derelict 
 bindings to classes however when i use the CSFML methods to 
 destroy the objects it causes a crash.

 I have made a post in the SFML>D forum because they have 
 syntax highlighting for D so this kind of post looks nicer 
 but the link is here:

 http://en.sfml-dev.org/forums/index.php?topic=10005.0

 There is a minimal code example there and a better 
 explanation.

 Can anyone help me with why this is happening?
Why would you call a destroy() on a this object inside ~this()? And accessing allocated by GC objects inside destructor is not safe, because they may be collected before running the destructor.
I am sorry if i am being dim but i thought that the sfml objects are not GC objects so it will exist forever until i call its destroy function so why cant this be done in the destructor? Unless you mean the pointer is being destroyed before the destructor is being called?
I do not know this library, but if you get InvalidMemoryOperationError it likely mean that you call in class dtor some function, which causes GC allocation. In your case it seems that you call sfImage_destroy(image) which might do such things.
Dec 16 2012
parent reply "Nekroze" <nekroze eturnilnetwork.com> writes:
On Sunday, 16 December 2012 at 17:14:55 UTC, Maxim Fomin wrote:
 On Sunday, 16 December 2012 at 15:21:46 UTC, Nekroze wrote:
 On Sunday, 16 December 2012 at 14:59:32 UTC, Maxim Fomin wrote:
 On Sunday, 16 December 2012 at 14:42:57 UTC, Nekroze wrote:
 I am trying to do some wrapping of the CSFML derelict 
 bindings to classes however when i use the CSFML methods to 
 destroy the objects it causes a crash.

 I have made a post in the SFML>D forum because they have 
 syntax highlighting for D so this kind of post looks nicer 
 but the link is here:

 http://en.sfml-dev.org/forums/index.php?topic=10005.0

 There is a minimal code example there and a better 
 explanation.

 Can anyone help me with why this is happening?
Why would you call a destroy() on a this object inside ~this()? And accessing allocated by GC objects inside destructor is not safe, because they may be collected before running the destructor.
I am sorry if i am being dim but i thought that the sfml objects are not GC objects so it will exist forever until i call its destroy function so why cant this be done in the destructor? Unless you mean the pointer is being destroyed before the destructor is being called?
I do not know this library, but if you get InvalidMemoryOperationError it likely mean that you call in class dtor some function, which causes GC allocation. In your case it seems that you call sfImage_destroy(image) which might do such things.
sfImage_destroy is purely a binding to a c function in a dll. It has no knowledge of the GC or anything which is why the image will live forever unless i call that function. SFML is a c++ OO based graphics library, in order to provide a c binding they made a C wrapper around all the OO stuff so the object, its all handled using C functions, needs to have its destructor called manually with the C destroy functions. With the D wrapper for this (Derelict3) there is no actual function for these its just some kind of pass through binding to the dll so the above, as far as i can understand, still holds true. This is why i have come to the belief that i should be perfectly able to call this destroy function in the destructor because what i am calling destroy on is an object that is created in C++ but accessed through C functions which have just been imported and bound to D names.
Dec 16 2012
parent reply "Mike Parker" <aldacron gmail.com> writes:
First, please take all Derelict trouble-shooting problems to the 
Derelict forums[1]. I never check the sfml forums. I do check the 
newsgroups regularly, but these newsgroups are not generally the 
place to look for help with Derelict problems. Plus, by posting 
in other places, you are making it more unlikely that future 
users with the same problem will find an answer.


On Sunday, 16 December 2012 at 17:20:55 UTC, Nekroze wrote:
 I am sorry if i am being dim but i thought that the sfml 
 objects are not GC objects so it will exist forever until i 
 call its destroy function so why cant this be done in the 
 destructor? Unless you mean the pointer is being destroyed 
 before the destructor is being called?
You are correct in that the sfImage instance is not GCed and will continue to stay resident in memory. But *your* Image class *is* GCed. You cannot, ever, rely on D destructors to clean up external resources. This is because you have no idea when, if, or in what order they will be called during runtime. They *will* be called when the program exits and the GC cleans up, but that is where you are running into your problem. See below.
 sfImage_destroy is purely a binding to a c function in a dll. 
 It has no knowledge of the GC or anything which is why the 
 image will live forever unless i call that function.

 SFML is a c++ OO based graphics library, in order to provide a 
 c binding they made a C wrapper around all the OO stuff so the 
 object, its all handled using C functions, needs to have its 
 destructor called manually with the C destroy functions. With 
 the D wrapper for this (Derelict3) there is no actual function 
 for these its just some kind of pass through binding to the dll 
 so the above, as far as i can understand, still holds true.

 This is why i have come to the belief that i should be 
 perfectly able to call this destroy function in the destructor 
 because what i am calling destroy on is an object that is 
 created in C++ but accessed through C functions which have just 
 been imported and bound to D names.
You have to understand that Derelict is a dynamic binding and not a static one. In this sort of binding, all of the functions you call are actually function pointers. When you call DerelictSFML2.load, Derelict is loading the shared library for you and making sure the function pointers are pointing to the write places. In a static binding where you would link with a static library, a Windows DLL import library, or directly with an shared object file on Posix systems, the shared library is loaded automatically and you call the functions normally rather than through pointers ("bound to D names", in other words). Any call to load a library into memory should generally be matched by a call to unload it. All Derelict bindings include a module destructor that automatically unloads its shared library at program exit. So here's what's happening to you. When your main function exits, the runtime starts the cleanup process. It runs the module destructors *before* cleaning up the GC. So DerelictSFML2's module destructor is run, the CSFML2 library is unloaded from memory, then after that the GC's cleanup begins and, at some point, the destructor on your Image class instance is called. Only now, when you call sfImage_destroy the library was already unloaded by the module destructor so the function pointer is no longer valid. Boom! You have a crash. Perhaps it would be ok for me to remove the module destructors and let the OS just free up the libraries when the process exits, but I'm not going to do that. Regardless, it doesn't change the fact that you should never, ever, ever rely on D class destructors for this sort of thing.
Dec 16 2012
next sibling parent reply "Mike Parker" <aldacron gmail.com> writes:
On Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:
 First, please take all Derelict trouble-shooting problems to 
 the Derelict forums[1]. I never check the sfml forums. I do 
 check the newsgroups regularly, but these newsgroups are not 
 generally the place to look for help with Derelict problems. 
 Plus, by posting in other places, you are making it more 
 unlikely that future users with the same problem will find an 
 answer.
[1]http://dblog.aldacron.net/forum/index.ph
Dec 16 2012
parent reply "Nekroze" <nekroze eturnilnetwork.com> writes:
On Monday, 17 December 2012 at 04:42:49 UTC, Mike Parker wrote:
 On Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:
 First, please take all Derelict trouble-shooting problems to 
 the Derelict forums[1]. I never check the sfml forums. I do 
 check the newsgroups regularly, but these newsgroups are not 
 generally the place to look for help with Derelict problems. 
 Plus, by posting in other places, you are making it more 
 unlikely that future users with the same problem will find an 
 answer.
[1]http://dblog.aldacron.net/forum/index.ph
Sorry about not posting on the derelict forums, i cant remember exactly what happened but i made an account and it said i have to wait for authentication or something so i couldn't post... may have it confused with another forum but yeah will do in the future when i can post there. Anyways so if i understand right the sfml objects wont delete themselves until the process exits right but what if i am in the middle of the process say in a game and i want to load another level i need to destroy the resources from the last level with the sfml destroy functions right. I just wanted that to be done automatically rather then having to have a destroy method that i must manually call from my class. So what i am getting here is that either A: having it in the destructor will work solong as the GC cleanup is called before the end of main because that is when sfml is unloaded OR B: I just have to have a manual destroy method in my class too to release the sfml objects?
Dec 16 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-12-17 07:45, Nekroze wrote:

 So what i am getting here is that either A: having it in the destructor
 will work solong as the GC cleanup is called before the end of main
 because that is when sfml is unloaded OR B: I just have to have a manual
 destroy method in my class too to release the sfml objects?
You cannot trust that the GC will collect at all. Although if the function pointers in the bindings are still active and you don't need to rely on the order of destruction you should be pretty safe, since your not destroying GC memory. The safest is to either: A. Manually call a destroy/delete function B. Call a destroy/delete function in a scope(exit) block (basically the same as A) C. Use a struct and call a destroy/delete function in its destructor. -- /Jacob Carlborg
Dec 16 2012
parent reply "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
I am somewhat confused by some things that are being talked about 
in this thread.

Mike Parker said that this Image is handled by GC. Would that 
mean that any class members are handled by the GC too? If so, 
wouldn't the sfImage* be collected by the GC?

If not, and you DO need to manually delete the pointer, is there 
anything wrong with something like:

~this
{
     destroy(image);
}


I am just thinking that it would suck to have to manually call 
destroy/delete on each object before exiting main. I tested this, 
and I didn't get any memory errors, so I can assume it is 
working? I did get an error if I used delete image, however. 
What's the difference between the two?

On Monday, 17 December 2012 at 07:25:06 UTC, Jacob Carlborg wrote:
 C. Use a struct and call a destroy/delete function in its 
 destructor.
And how does calling destroy/delete in a struct destructor differ from doing the same in a class destructor? I too would like to make sure I am not getting any memory leaks! On 2012-12-17 07:45, Nekroze wrote:
Sorry about not posting on the derelict forums, i cant remember 
exactly what happened but i made an account and it said i have 
to wait for authentication or something so i couldn't post... 
may have it confused with another forum but yeah will do in the 
future when i can post there.
It was a different forum. I got the same error that you did on the same forum. Nice to know there's this one dedicated to Derelict! I just made an account, so I'll see you in there!
Dec 17 2012
next sibling parent reply "Mike Parker" <aldacron gmail.com> writes:
On Monday, 17 December 2012 at 08:23:02 UTC, Jeremy DeHaan wrote:
 I am somewhat confused by some things that are being talked 
 about in this thread.

 Mike Parker said that this Image is handled by GC. Would that 
 mean that any class members are handled by the GC too? If so, 
 wouldn't the sfImage* be collected by the GC?
Any class members that are allocated on the D heap, sure. But the memory for sfImage is allocated by sfml outside of the D garbage collector's heap. The GC knows nothing about it. The GC can only free the memory it controls. When you allocate memory from a C library, you are responsible for cleaning it up. But, you cannot rely on a class destructor to do this for you. There is absolutely no guarantee about when or if class destructors will be run, or in what order, during program execution. So relying on a destructor is totally nondeterministic. And when using Derelict, if you try to call a bound library in a destructor, but the object is not released until the GC cleans up at program exit, you will always get a crash because Derelict will have already unloaded
 If not, and you DO need to manually delete the pointer, is 
 there anything wrong with something like:

 ~this
 {
     destroy(image);
 }
See above. You should never do this sort of thing in a destructor.
 I am just thinking that it would suck to have to manually call 
 destroy/delete on each object before exiting main. I tested 
 this, and I didn't get any memory errors, so I can assume it is 
 working? I did get an error if I used delete image, however. 
 What's the difference between the two?
I'm not quite sure what you are referring to when you say, "I tested this." Which? Freeing the image in a destructor? I always clean up manually. When making a game in D, this is the approach I take. ================== module mygame; private void init() { // Throw Error on failure DerelictFoo.load(); graphicsInit(); audioInit(); ... } private void term() { // Release all resources here ... audioTerm(); graphicsTerm(); } void main(string[] args) { scope(exit) term(); init(); gameLoop(); } ================= Then in each subsystem, there's always some sort of list/manager/registry that managers different objects. Each of these will have initialize/terminate method/free functions, and all of the objects they track that need to cleanup will have a terminate method. For example, I might have an aa in the graphics module that serves as a texture registry. And each texture will have a terminate method that calles into OpenGL to delete a texture. ========= private Texture[string] _texRegistry; class Texture { private uint id; public void term() { glDeleteTextures(1, &id); } } void gfxTerm() { if(!DerelictGL3.isLoaded) return; foreach(tex; _texRegistry.byValue) tex.term(); clear(_texRegistry); } ========= The scope(exit) in the main method ensures that this termination chain is run every time the app exits regardless of the reason -- even when the Derelict libraries fail to load. So, if I'm going to be calling into the bound libraries in any of the termination functions, then at the top of the manager-level terminators I test to make sure the lib is loaded. If it isn't, I exit quick. Because loading the libraries is always the very first thing I do, if the libraries aren't loaded then there aren't going to be any resources to release. For any short lived objects, I still don't rely on destructors but call the terminator manually. Perhaps it's my years of programming in C without ctors and dtors, but I find this process painless and just as easy as using a destructor.
Dec 17 2012
parent reply "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:

have pretty much 0 experience when it comes to handling memory 
myself(let alone working with a binding to another language) and 
I haven't read my D book as much as I would like.

 I'm not quite sure what you are referring to when you say, "I 
 tested this." Which? Freeing the image in a destructor?
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.
 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? 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? 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! Sorry if I say silly things. I am but a young programmer trying to gain knowledge!
Dec 17 2012
parent reply "Mike Parker" <aldacron gmail.com> writes:
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!
Dec 17 2012
parent reply "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
 It's not the only way, but it's the easiest way.
What are some other ways? I am just curious. Also, if we were able to know the size of the object the pointer is referring to, couldn't we then add it to the GC? It sounds like a pretty complicated way, but wouldn't that be a good way if it were possible?
Dec 17 2012
parent reply "Mike Parker" <aldacron gmail.com> writes:
On Monday, 17 December 2012 at 22:08:08 UTC, Jeremy DeHaan wrote:
 It's not the only way, but it's the easiest way.
What are some other ways? I am just curious.
You could use module destructors to cleanup at program exit and use RAII via struct destructors for short-lived objects.
 Also, if we were able to know the size of the object the 
 pointer is referring to, couldn't we then add it to the GC? It 
 sounds like a pretty complicated way, but wouldn't that be a 
 good way if it were possible?
No, that's a bad idea. What if the C library you are using maintains some sort of internal bookkeeping related to the pointer? What if it keeps a copy of the pointer internally? If the GC collects your D-side pointer, how is the C library supposed to know it's time to cleanup everything associated with that pointer?
Dec 17 2012
parent "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
On Tuesday, 18 December 2012 at 01:24:43 UTC, Mike Parker wrote:

 No, that's a bad idea. What if the C library you are using 
 maintains some sort of internal bookkeeping related to the 
 pointer? What if it keeps a copy of the pointer internally? If 
 the GC collects your D-side pointer, how is the C library 
 supposed to know it's time to cleanup everything associated 
 with that pointer?
I definitely hadn't considered that. I was mainly talking about the CSFML library, but I think even then trying to add the pointers into the GC would cause the problems you mention. Thanks for all the insight!
Dec 17 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-12-17 09:23, Jeremy DeHaan wrote:

 And how does calling destroy/delete in a struct destructor differ from
 doing the same in a class destructor? I too would like to make sure I am
 not getting any memory leaks!
Because there are guarantees how and when a destructor for a struct is called. You cannot rely on a destructor for a class when it's called, in what order they are called or if they're called at all. import std.stdio; struct Foo { ~this () { writeln("destroying Foo"); } } class Bar { ~this () { writeln("destroying Bar"); } } void foobar () { auto foo = Foo(); auto bar = new Bar(); // the destructor of "foo" _will always_ be called here // the destructor of "bar" _may_ be called here } void main () { foobar(); } -- /Jacob Carlborg
Dec 17 2012
parent reply "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
On Monday, 17 December 2012 at 09:52:08 UTC, Jacob Carlborg wrote:
 On 2012-12-17 09:23, Jeremy DeHaan wrote:

 And how does calling destroy/delete in a struct destructor 
 differ from
 doing the same in a class destructor? I too would like to make 
 sure I am
 not getting any memory leaks!
Because there are guarantees how and when a destructor for a struct is called. You cannot rely on a destructor for a class when it's called, in what order they are called or if they're called at all. import std.stdio; struct Foo { ~this () { writeln("destroying Foo"); } } class Bar { ~this () { writeln("destroying Bar"); } } void foobar () { auto foo = Foo(); auto bar = new Bar(); // the destructor of "foo" _will always_ be called here // the destructor of "bar" _may_ be called here } void main () { foobar(); }
Thanks! This is also good to know! Does that mean that putting some form of delete in a struct destructor will be called to delete contents or is that still considered unsafe? And why don't classes have the same guarantee? Is it because they are a reference type and thus handled by the GC rather than being a value type?
Dec 17 2012
parent reply "Nekroze" <nekroze eturnilnetwork.com> writes:
On Monday, 17 December 2012 at 10:56:23 UTC, Jeremy DeHaan wrote:
 Does that mean that putting some form of delete in a struct 
 destructor will be called to delete contents or is that still 
 considered unsafe?


 And why don't classes have the same guarantee? Is it because 
 they are a reference type and thus handled by the GC rather 
 than being a value type?
Structs have their destructors called, as far as i understand, as soon as you go out of the scope they are defined in. Not sure how that works with structs that are members of a class but i assume that has the same problems as a class's destructor. Classes don't have this guarantee because when they go out of scope, again as far as i understand, they are just added to the gc list of things that may need to be cleared (presuming they are not stored elsewhere still?) and are cleaned whenever the GC feels like it. Now what i was thinking as a solution, would it be possible to manually run the GC cleanup pass at the end of main this way we know that the GC cleanup would run before main exits and thus sfml gets unloaded. Although i believe this still doesn't guarantee that it will think the class is fit for deconstruction at that point so it may still no work but just a thought.
Dec 17 2012
next sibling parent "Nekroze" <nekroze eturnilnetwork.com> writes:
On Monday, 17 December 2012 at 12:08:29 UTC, Nekroze wrote:
 Now what i was thinking as a solution, would it be possible to 
 manually run the GC cleanup pass at the end of main this way we 
 know that the GC cleanup would run before main exits and thus 
 sfml gets unloaded. Although i believe this still doesn't 
 guarantee that it will think the class is fit for 
 deconstruction at that point so it may still no work but just a 
 thought.
By this i mean core.memory.GC.collect() for example. Note i have never used core.memory to touch the gc or anything and am assuming this function does what i am talking about.
Dec 17 2012
prev sibling parent reply "Mike Parker" <aldacron gmail.com> writes:
On Monday, 17 December 2012 at 12:08:29 UTC, Nekroze wrote:
 Structs have their destructors called, as far as i understand, 
 as soon as you go out of the scope they are defined in. Not 
 sure how that works with structs that are members of a class 
 but i assume that has the same problems as a class's destructor.
Structs are stack objects (unless you allocate them with new and get a pointer). Stack objects will always have their destructors called when their scope exits. It's the only time you can rely on a destructor. What is the scope of a struct that is a member of a class? I haven't tested it (I generally don't use struct destructors) but I would guess that when the class destructor is run, any structs that are members are also destructed. But not before then. The same cannot be said of class instances that are class members, because they are also GCed object. Given class A a, which has a member instance of class B b, once 'a' is no longer referenced by the program, it does not mean that 'b' is also no longer referenced. There could be another reference to it somewhere else. So its eventual destruction will be completely independent from that of 'a'. Which is why you should never do anything like this: ~this() { destroy(b); }
 Classes don't have this guarantee because when they go out of 
 scope, again as far as i understand, they are just added to the 
 gc list of things that may need to be cleared (presuming they 
 are not stored elsewhere still?) and are cleaned whenever the 
 GC feels like it.
Class instances are marked for deallocation when the GC determines that there are no more references to them. Every time you allocate more memory, the GC will decide if it needs to free up any previously allocated memory. Different GCs will use different algorithms for this, so there's no way to have any influence over which objects are deallocated when.
 Now what i was thinking as a solution, would it be possible to 
 manually run the GC cleanup pass at the end of main this way we 
 know that the GC cleanup would run before main exits and thus 
 sfml gets unloaded. Although i believe this still doesn't 
 guarantee that it will think the class is fit for 
 deconstruction at that point so it may still no work but just a 
 thought.
There's no reason to do that. If you have any external resources to cleanup, just clean it up yourself. The init/term pattern I posted earlier works just fine.
Dec 17 2012
parent "Nekroze" <nekroze eturnilnetwork.com> writes:
On Monday, 17 December 2012 at 14:06:30 UTC, Mike Parker wrote:
 Now what i was thinking as a solution, would it be possible to 
 manually run the GC cleanup pass at the end of main this way 
 we know that the GC cleanup would run before main exits and 
 thus sfml gets unloaded. Although i believe this still doesn't 
 guarantee that it will think the class is fit for 
 deconstruction at that point so it may still no work but just 
 a thought.
There's no reason to do that. If you have any external resources to cleanup, just clean it up yourself. The init/term pattern I posted earlier works just fine.
I understand that your method would work and that's fair enough but as people have indicated they still want to keep GC feel across their code rather then some parts that need manual destruction or termination and other things that don't so i was thinking this may be a way of doing that. Just cause there is another way of doing it doesn't mean i don't want to know if the way i thought of is possible or not. Maybe since there (practically) has to be a manual destroy method when people are making these wrappers in D for things like SFML, if they still want to have the appearance or feeling of it still using the same GC'd scheme like the rest of D is to implement some kind of reference counting in the wrapper that is transparent so that to the user it seems like the rest of D. I am not interested in making a OO SFML wrapper myself but it seems some of the responders are so i am just trying to help in whatever limited way i can.
Dec 17 2012
prev sibling parent reply "Rob T" <rob ucora.com> writes:
On Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:
 First, please take all Derelict trouble-shooting problems to 
 the Derelict forums[1].
I'm posting here because I was unable to register with the derelict forum. I filled out the registration form and press the register button, then a page opens with this message. "An Error Has Occurred!" I tried a few times being very careful not to make any mistakes. I was going to post asking for a very small change to the derelict2 make process so that I could specify the compiler path. This is so I can pick a different version of dmd (or gdc, or ldc) as I have multiple versions installed (release and pre-release). I modded the make files to allow me to specify the compiler by full path, so I'm OK for now, this is just a suggested improvement for you to consider. I hope you can help me get registered. Thanks! --rt
Dec 17 2012
next sibling parent reply "Mike Parker" <aldacron gmail.com> writes:
On Tuesday, 18 December 2012 at 07:36:09 UTC, Rob T wrote:
 On Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:
 First, please take all Derelict trouble-shooting problems to 
 the Derelict forums[1].
I'm posting here because I was unable to register with the derelict forum. I filled out the registration form and press the register button, then a page opens with this message. "An Error Has Occurred!"
Sorry, I've no idea what's going on there.
 I hope you can help me get registered. Thanks!
If you email me the user name you want, I'll register an account for you.
Dec 18 2012
parent "Mike Parker" <aldacron gmail.com> writes:
On Tuesday, 18 December 2012 at 08:14:01 UTC, Mike Parker wrote:
 On Tuesday, 18 December 2012 at 07:36:09 UTC, Rob T wrote:
 On Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:
 First, please take all Derelict trouble-shooting problems to 
 the Derelict forums[1].
I'm posting here because I was unable to register with the derelict forum. I filled out the registration form and press the register button, then a page opens with this message. "An Error Has Occurred!"
Sorry, I've no idea what's going on there.
 I hope you can help me get registered. Thanks!
If you email me the user name you want, I'll register an account for you.
aldacron gmail.com
Dec 18 2012
prev sibling next sibling parent "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
On Tuesday, 18 December 2012 at 07:36:09 UTC, Rob T wrote:
 On Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:
 First, please take all Derelict trouble-shooting problems to 
 the Derelict forums[1].
I'm posting here because I was unable to register with the derelict forum. I filled out the registration form and press the register button, then a page opens with this message. "An Error Has Occurred!" I tried a few times being very careful not to make any mistakes. I was going to post asking for a very small change to the derelict2 make process so that I could specify the compiler path. This is so I can pick a different version of dmd (or gdc, or ldc) as I have multiple versions installed (release and pre-release). I modded the make files to allow me to specify the compiler by full path, so I'm OK for now, this is just a suggested improvement for you to consider. I hope you can help me get registered. Thanks! --rt
I had the same error actually. I just tried until it worked, which was the second time I tried.
Dec 18 2012
prev sibling parent reply "Mike Parker" <aldacron gmail.com> writes:
On Tuesday, 18 December 2012 at 07:36:09 UTC, Rob T wrote:
 On Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:
 First, please take all Derelict trouble-shooting problems to 
 the Derelict forums[1].
I'm posting here because I was unable to register with the derelict forum. I filled out the registration form and press the register button, then a page opens with this message. "An Error Has Occurred!" I tried a few times being very careful not to make any mistakes.
I *think* I've got it sorted. If you try again, it should work.
Dec 18 2012
parent "Rob T" <rob ucora.com> writes:
On Tuesday, 18 December 2012 at 13:47:43 UTC, Mike Parker wrote:
 I *think* I've got it sorted. If you try again, it should work.
I tried it again just now and it worked. Thanks! --rt
Dec 18 2012