digitalmars.D.learn - Derelict SFML destructor crashes
- Nekroze (9/9) Dec 16 2012 I am trying to do some wrapping of the CSFML derelict bindings to
- Maxim Fomin (4/13) Dec 16 2012 Why would you call a destroy() on a this object inside ~this()?
- Nekroze (6/24) Dec 16 2012 I am sorry if i am being dim but i thought that the sfml objects
- Nekroze (7/33) Dec 16 2012 To me it makes sense to use the sfml objects destroy function
- Maxim Fomin (6/32) Dec 16 2012 I do not know this library, but if you get
- Nekroze (16/49) Dec 16 2012 sfImage_destroy is purely a binding to a c function in a dll. It
- Mike Parker (41/61) Dec 16 2012 First, please take all Derelict trouble-shooting problems to the
- Mike Parker (2/9) Dec 16 2012 [1]http://dblog.aldacron.net/forum/index.ph
- Nekroze (18/28) Dec 16 2012 Sorry about not posting on the derelict forums, i cant remember
- Jacob Carlborg (12/16) Dec 16 2012 You cannot trust that the GC will collect at all. Although if the
- Jeremy DeHaan (24/31) Dec 17 2012 I am somewhat confused by some things that are being talked about
- Mike Parker (82/98) Dec 17 2012 Any class members that are allocated on the D heap, sure. But the
- Jeremy DeHaan (35/40) Dec 17 2012 Thanks for all the info, Mike. I come from a C# background, so I
- Mike Parker (78/114) Dec 17 2012 I've not yet used destroy and am not familiar with everything it
- Jeremy DeHaan (5/6) Dec 17 2012 What are some other ways? I am just curious.
- Mike Parker (9/15) Dec 17 2012 You could use module destructors to cleanup at program exit and
- Jeremy DeHaan (5/11) Dec 17 2012 I definitely hadn't considered that. I was mainly talking about
- Jacob Carlborg (26/29) Dec 17 2012 Because there are guarantees how and when a destructor for a struct is
- Jeremy DeHaan (8/38) Dec 17 2012 Thanks! This is also good to know!
- Nekroze (16/22) Dec 17 2012 Structs have their destructors called, as far as i understand, as
- Nekroze (4/11) Dec 17 2012 By this i mean core.memory.GC.collect() for example. Note i have
- Mike Parker (30/46) Dec 17 2012 Structs are stack objects (unless you allocate them with new and
- Nekroze (17/27) Dec 17 2012 I understand that your method would work and that's fair enough
- Rob T (16/18) Dec 17 2012 I'm posting here because I was unable to register with the
- Mike Parker (4/13) Dec 18 2012 If you email me the user name you want, I'll register an account
- Mike Parker (2/19) Dec 18 2012 aldacron@gmail.com
- Jeremy DeHaan (3/22) Dec 18 2012 I had the same error actually. I just tried until it worked,
- Mike Parker (2/11) Dec 18 2012 I *think* I've got it sorted. If you try again, it should work.
- Rob T (3/4) Dec 18 2012 I tried it again just now and it worked. Thanks!
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
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
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 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 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
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: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.On Sunday, 16 December 2012 at 14:42:57 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?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
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: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.On Sunday, 16 December 2012 at 14:42:57 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?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
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: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.On Sunday, 16 December 2012 at 14:59:32 UTC, Maxim Fomin wrote: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.On Sunday, 16 December 2012 at 14:42:57 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?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
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: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.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?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
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
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: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?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
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
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
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 unloadedIf 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
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 reasonThis 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
On Monday, 17 December 2012 at 10:39:56 UTC, Jeremy DeHaan wrote: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.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.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.The scope(exit) in the main method ensures that this termination chain is run every time the app exits regardless of the reasonThis 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?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
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
On Monday, 17 December 2012 at 22:08:08 UTC, Jeremy DeHaan wrote:You could use module destructors to cleanup at program exit and use RAII via struct destructors for short-lived objects.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?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
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
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
On Monday, 17 December 2012 at 09:52:08 UTC, Jacob Carlborg wrote:On 2012-12-17 09:23, Jeremy DeHaan wrote: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?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(); }
Dec 17 2012
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
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
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
On Monday, 17 December 2012 at 14:06:30 UTC, Mike Parker wrote: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.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
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
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:Sorry, I've no idea what's going on there.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 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
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:aldacron gmail.comOn Monday, 17 December 2012 at 04:40:39 UTC, Mike Parker wrote:Sorry, I've no idea what's going on there.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 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
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:I had the same error actually. I just tried until it worked, which was the second time I tried.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 18 2012
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:I *think* I've got it sorted. If you try again, it should work.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.
Dec 18 2012
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