www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - free causes exception

reply Igor <Vladamir.I google.com> writes:
I have successfully malloc'ed an object but when I go to free it 
in the destructor I get an exception. The destructor simply has

~this() // destructor for Foo
{
     core.stdc.stdlib.free(&this);
}


auto buffer = core.stdc.stdlib.malloc(__traits(classInstanceSize, 
App))[0..__traits(classInstanceSize, App)];
auto app = cast(App)emplace!App(buffer[]);

I tried to retain a ptr to buffer and free that but still no 
good. I also get a depreciation warning that &this is not an 
lvalue. Hopefully I don't have to keep a ptr around to this 
simply to free it and avoid future issues?

So how am I suppose to free an object?
Jan 26 2016
next sibling parent reply Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
V Tue, 26 Jan 2016 14:20:29 +0000
Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
napsáno:

 I have successfully malloc'ed an object but when I go to free it 
 in the destructor I get an exception. The destructor simply has
 
 ~this() // destructor for Foo
 {
      core.stdc.stdlib.free(&this);
 }
 
 
 auto buffer = core.stdc.stdlib.malloc(__traits(classInstanceSize, 
 App))[0..__traits(classInstanceSize, App)];
 auto app = cast(App)emplace!App(buffer[]);
 
 I tried to retain a ptr to buffer and free that but still no 
 good. I also get a depreciation warning that &this is not an 
 lvalue. Hopefully I don't have to keep a ptr around to this 
 simply to free it and avoid future issues?
 
 So how am I suppose to free an object?
 
 
core.stdc.stdlib.free(cast(void *)this);
Jan 26 2016
parent reply Igor <Vladamir.I google.com> writes:
On Tuesday, 26 January 2016 at 14:48:48 UTC, Daniel Kozak wrote:
 V Tue, 26 Jan 2016 14:20:29 +0000
 Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
 napsáno:

 [...]
core.stdc.stdlib.free(cast(void *)this);
I still get an exception: Exception thrown at 0x00007FF6C7CA3700 in test.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
Jan 26 2016
parent Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
V Tue, 26 Jan 2016 15:24:00 +0000
Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
napsáno:

 On Tuesday, 26 January 2016 at 14:48:48 UTC, Daniel Kozak wrote:
 V Tue, 26 Jan 2016 14:20:29 +0000
 Igor via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
 napsáno:
  
 [...]  
core.stdc.stdlib.free(cast(void *)this);
I still get an exception: Exception thrown at 0x00007FF6C7CA3700 in test.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
Can you post full code?
Jan 26 2016
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/26/2016 06:20 AM, Igor wrote:
 I have successfully malloc'ed an object but when I go to free it in the
 destructor I get an exception. The destructor simply has

 ~this() // destructor for Foo
 {
      core.stdc.stdlib.free(&this);
 }
That design suggests a complexity regarding object responsibilities: Assuming that the object was constructed on a piece of memory that it did *not* allocate, the memory was owned by somebody else. In that case and in general, freeing the memory should be the responsibility of that other somebody as well. Even if it is acceptable, you must also make sure that opAssign() and post-blit do the right thing: no two object should own the same piece of memory. Ali
Jan 26 2016
parent reply Igor <Vladamir.I google.com> writes:
On Tuesday, 26 January 2016 at 19:34:22 UTC, Ali Çehreli wrote:
 On 01/26/2016 06:20 AM, Igor wrote:
 I have successfully malloc'ed an object but when I go to free
it in the
 destructor I get an exception. The destructor simply has

 ~this() // destructor for Foo
 {
      core.stdc.stdlib.free(&this);
 }
That design suggests a complexity regarding object responsibilities: Assuming that the object was constructed on a piece of memory that it did *not* allocate, the memory was owned by somebody else. In that case and in general, freeing the memory should be the responsibility of that other somebody as well. Even if it is acceptable, you must also make sure that opAssign() and post-blit do the right thing: no two object should own the same piece of memory. Ali
That shouldn't be the case. I allocate in a static method called New once. I then deallocate in the destructor. Basically just as one would do in C++. I'm not sure about opAssign and post-blit class Foo { ~this() // destructor for Foo { core.stdc.stdlib.free(cast(void *)this); } // Creates a Foo static public Foo New() { auto buffer = core.stdc.stdlib.malloc(__traits(classInstanceSize, Foo))[0..__traits(classInstanceSize, Foo)]; auto app = cast(Foo)emplace!Foo(buffer[]); } } hence auto f = Foo.New(); then .destroy(f); which is where the crash happens. If I don't destroy, it works fine + memory leak.
Jan 26 2016
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/26/2016 01:21 PM, Igor wrote:

 I allocate in a static method called New once. I then deallocate in the
 destructor. Basically just as one would do in C++.
I would never do that in even C++. I don't know any C++ idiom that warrants 'delete this' where superior alternatives cannot be used.
 class Foo
 {
      ~this() // destructor for Foo
      {
          core.stdc.stdlib.free(cast(void *)this);
      }

          // Creates a Foo
      static public Foo New()
      {
          auto buffer =
 core.stdc.stdlib.malloc(__traits(classInstanceSize,
 Foo))[0..__traits(classInstanceSize, Foo)];
          auto app = cast(Foo)emplace!Foo(buffer[]);
          }
 }

 hence

 auto f = Foo.New();

 then .destroy(f);
Something else in the program must have something to do with it. I don't see the crash with the following program: import std.stdio; import core.stdc.stdlib; import std.conv; class Foo { ~this() // destructor for Foo { core.stdc.stdlib.free(cast(void *)this); } // Creates a Foo static public Foo New() { auto buffer = core.stdc.stdlib.malloc( __traits(classInstanceSize, Foo)) [0..__traits(classInstanceSize, Foo)]; auto app = cast(Foo)emplace!Foo(buffer[]); return app; } } void main() { auto f = Foo.New(); .destroy(f); } Ali
Jan 26 2016
prev sibling parent Kagamin <spam here.lot> writes:
On Tuesday, 26 January 2016 at 21:21:29 UTC, Igor wrote:
 That shouldn't be the case. I allocate in a static method 
 called New once. I then deallocate in the destructor. Basically 
 just as one would do in C++.
You can't deallocate in destructor in C++, because an object can be embedded in another object, so if it's destructor deallocates itself, it will deallocate the container object before it finishes its destruction. It's delete operator that deallocates memory in C++.
Jan 27 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/26/16 9:20 AM, Igor wrote:
 I have successfully malloc'ed an object but when I go to free it in the
 destructor I get an exception. The destructor simply has

 ~this() // destructor for Foo
 {
      core.stdc.stdlib.free(&this);
 }


 auto buffer = core.stdc.stdlib.malloc(__traits(classInstanceSize,
 App))[0..__traits(classInstanceSize, App)];
 auto app = cast(App)emplace!App(buffer[]);

 I tried to retain a ptr to buffer and free that but still no good. I
 also get a depreciation warning that &this is not an lvalue. Hopefully I
 don't have to keep a ptr around to this simply to free it and avoid
 future issues?

 So how am I suppose to free an object?
Don't do it in the destructor. I can only imagine that you are triggering the destructor with destroy? In this case, destroy is calling the destructor, but then tries to zero the memory (which has already been freed). There is a mechanism D supports (but I believe is deprecated) by overriding new and delete. You may want to try that. It's deprecated, but has been for years and years, and I doubt it's going away any time soon. A class shouldn't care how it's allocated or destroyed. That is for the memory manager to worry about. -Steve
Jan 26 2016
parent reply Igor <Vladamir.I google.com> writes:
On Tuesday, 26 January 2016 at 20:17:20 UTC, Steven Schveighoffer 
wrote:
 On 1/26/16 9:20 AM, Igor wrote:
 I have successfully malloc'ed an object but when I go to free 
 it in the
 destructor I get an exception. The destructor simply has

 ~this() // destructor for Foo
 {
      core.stdc.stdlib.free(&this);
 }


 auto buffer = 
 core.stdc.stdlib.malloc(__traits(classInstanceSize,
 App))[0..__traits(classInstanceSize, App)];
 auto app = cast(App)emplace!App(buffer[]);

 I tried to retain a ptr to buffer and free that but still no 
 good. I
 also get a depreciation warning that &this is not an lvalue. 
 Hopefully I
 don't have to keep a ptr around to this simply to free it and 
 avoid
 future issues?

 So how am I suppose to free an object?
Don't do it in the destructor. I can only imagine that you are triggering the destructor with destroy? In this case, destroy is calling the destructor, but then tries to zero the memory (which has already been freed). There is a mechanism D supports (but I believe is deprecated) by overriding new and delete. You may want to try that. It's deprecated, but has been for years and years, and I doubt it's going away any time soon. A class shouldn't care how it's allocated or destroyed. That is for the memory manager to worry about.
um? Memory manager? I am doing it manually C++ style so I don't have to worry about the god forsaken memory manager. Why is it so difficult? I create the object and release it when I need to. I can replace the destroy(f) with free(inline the code) but I don't see why that should matter. The whole point of destructors is to do this sort of stuff. That's why they were invented in the first place!?!
Jan 26 2016
next sibling parent ZombineDev <valid_email he.re> writes:
On Tuesday, 26 January 2016 at 21:23:28 UTC, Igor wrote:
 On Tuesday, 26 January 2016 at 20:17:20 UTC, Steven 
 Schveighoffer wrote:
 On 1/26/16 9:20 AM, Igor wrote:
 I have successfully malloc'ed an object but when I go to free 
 it in the
 destructor I get an exception. The destructor simply has

 ~this() // destructor for Foo
 {
      core.stdc.stdlib.free(&this);
 }


 auto buffer = 
 core.stdc.stdlib.malloc(__traits(classInstanceSize,
 App))[0..__traits(classInstanceSize, App)];
 auto app = cast(App)emplace!App(buffer[]);

 I tried to retain a ptr to buffer and free that but still no 
 good. I
 also get a depreciation warning that &this is not an lvalue. 
 Hopefully I
 don't have to keep a ptr around to this simply to free it and 
 avoid
 future issues?

 So how am I suppose to free an object?
Don't do it in the destructor. I can only imagine that you are triggering the destructor with destroy? In this case, destroy is calling the destructor, but then tries to zero the memory (which has already been freed). There is a mechanism D supports (but I believe is deprecated) by overriding new and delete. You may want to try that. It's deprecated, but has been for years and years, and I doubt it's going away any time soon. A class shouldn't care how it's allocated or destroyed. That is for the memory manager to worry about.
um? Memory manager? I am doing it manually C++ style so I don't have to worry about the god forsaken memory manager. Why is it so difficult? I create the object and release it when I need to. I can replace the destroy(f) with free(inline the code) but I don't see why that should matter. The whole point of destructors is to do this sort of stuff. That's why they were invented in the first place!?!
Why not simply: class Foo { this(Arg1, Arg2) { ... } ... } // Option A: import std.typecons : scoped; auto foo = scoped!Foo(arg1, arg2); // Option B: import std.experimental.allocator : make, dispose; import std.experimental.allocator.mallocator; auto foo = Mallocator.instance.make!Foo(arg1, arg2); scope(exit) Mallocator.instance.dispose(foo); http://dlang.org/phobos/std_experimental_allocator
Jan 26 2016
prev sibling next sibling parent ZombineDev <valid_email he.re> writes:
On Tuesday, 26 January 2016 at 21:23:28 UTC, Igor wrote:
 On Tuesday, 26 January 2016 at 20:17:20 UTC, Steven 
 Schveighoffer wrote:
 On 1/26/16 9:20 AM, Igor wrote:
 [...]
Don't do it in the destructor. I can only imagine that you are triggering the destructor with destroy? In this case, destroy is calling the destructor, but then tries to zero the memory (which has already been freed). There is a mechanism D supports (but I believe is deprecated) by overriding new and delete. You may want to try that. It's deprecated, but has been for years and years, and I doubt it's going away any time soon. A class shouldn't care how it's allocated or destroyed. That is for the memory manager to worry about.
um? Memory manager? I am doing it manually C++ style so I don't have to worry about the god forsaken memory manager. Why is it so difficult? I create the object and release it when I need to. I can replace the destroy(f) with free(inline the code) but I don't see why that should matter. The whole point of destructors is to do this sort of stuff. That's why they were invented in the first place!?!
Destructors are meant to destroy the members of the object, not the object itself. An object should be freed by the destructor of its owner and so on, transitively. A class should not have a hard coded dependency on malloc/free, or the GC. You should strive to design it in such a way that the clients of the class are free to decide how to manage its memory.
Jan 26 2016
prev sibling next sibling parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 26 January 2016 at 21:23:28 UTC, Igor wrote:

 um? Memory manager? I am doing it manually C++ style so I don't 
 have to worry about the god forsaken memory manager. Why is it 
 so difficult? I create the object and release it when I need to.
He's talking about *your* memory manager, whatever system you have set up to allocate and deallocate memory.
 I can replace the destroy(f) with free(inline the code) but I 
 don't see why that should matter. The whole point of 
 destructors is to do this sort of stuff. That's why they were 
 invented in the first place!?!
Not in D! You have to get your mind out of C++ mode when programming in D. D is not C++, no matter how similar they are, and there are idioms that work well in C++ that do not work in D. There are cases where D's destructors behave like those in C++, but not always. Since this approach is failing for you, I suggest you make a function or template that can take any object you've manually allocated, call destroy on it, then deallocate it. The destructor can still clean up any resources the object maintains, but the responsibility for deallocating the object will be taken out of the destructor. It also ensures that deallocation does not interfere with the operation of destroy.
Jan 26 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/26/16 4:23 PM, Igor wrote:
 On Tuesday, 26 January 2016 at 20:17:20 UTC, Steven Schveighoffer wrote:
 On 1/26/16 9:20 AM, Igor wrote:
 I have successfully malloc'ed an object but when I go to free it in the
 destructor I get an exception. The destructor simply has

 ~this() // destructor for Foo
 {
      core.stdc.stdlib.free(&this);
 }


 auto buffer = core.stdc.stdlib.malloc(__traits(classInstanceSize,
 App))[0..__traits(classInstanceSize, App)];
 auto app = cast(App)emplace!App(buffer[]);

 I tried to retain a ptr to buffer and free that but still no good. I
 also get a depreciation warning that &this is not an lvalue. Hopefully I
 don't have to keep a ptr around to this simply to free it and avoid
 future issues?

 So how am I suppose to free an object?
Don't do it in the destructor. I can only imagine that you are triggering the destructor with destroy? In this case, destroy is calling the destructor, but then tries to zero the memory (which has already been freed). There is a mechanism D supports (but I believe is deprecated) by overriding new and delete. You may want to try that. It's deprecated, but has been for years and years, and I doubt it's going away any time soon. A class shouldn't care how it's allocated or destroyed. That is for the memory manager to worry about.
um? Memory manager? I am doing it manually C++ style so I don't have to worry about the god forsaken memory manager. Why is it so difficult? I create the object and release it when I need to.
As Mike said, I mean whatever you are using for memory management. The class is not responsible for allocating or deallocating itself, just initializing itself and deinitializing itself. So if you use malloc and free, that is your memory manager.
 I can replace the destroy(f) with free(inline the code) but I don't see
 why that should matter. The whole point of destructors is to do this
 sort of stuff. That's why they were invented in the first place!?!
It isn't even this way in C++. No destructors deallocate 'this'. All D destructors should destroy all the members. And generally speaking, if you ever plan to use a class with the GC, you should only destroy non-GC members. The GC members may already be destroyed. -Steve
Jan 27 2016
parent reply Igor <Vladamir.I google.com> writes:
On Wednesday, 27 January 2016 at 14:31:20 UTC, Steven 
Schveighoffer wrote:
 On 1/26/16 4:23 PM, Igor wrote:
 On Tuesday, 26 January 2016 at 20:17:20 UTC, Steven 
 Schveighoffer wrote:
 [...]
um? Memory manager? I am doing it manually C++ style so I don't have to worry about the god forsaken memory manager. Why is it so difficult? I create the object and release it when I need to.
As Mike said, I mean whatever you are using for memory management. The class is not responsible for allocating or deallocating itself, just initializing itself and deinitializing itself. So if you use malloc and free, that is your memory manager.
 I can replace the destroy(f) with free(inline the code) but I 
 don't see
 why that should matter. The whole point of destructors is to 
 do this
 sort of stuff. That's why they were invented in the first 
 place!?!
It isn't even this way in C++. No destructors deallocate 'this'. All D destructors should destroy all the members. And generally speaking, if you ever plan to use a class with the GC, you should only destroy non-GC members. The GC members may already be destroyed. -Steve
There needs to be better docs on this? Or at least someone needs to provide a link! ;) Why can there be an "deplace" equivalent to emplace? Everone says it's so easy not to use the GC in D yet I can't seem to find any real world examples ;/
Jan 27 2016
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/27/16 5:35 PM, Igor wrote:
 On Wednesday, 27 January 2016 at 14:31:20 UTC, Steven Schveighoffer wrote:
 All D destructors should destroy all the members. And generally
 speaking, if you ever plan to use a class with the GC, you should only
 destroy non-GC members. The GC members may already be destroyed.
BTW, I wrote that wrong, I should have said "All D destructors *should do is* destroy all the members." In other words, you shouldn't do anything but destroy members.
 There needs to be better docs on this? Or at least someone needs to
 provide a link! ;)
http://dlang.org/spec/class.html#destructors "Furthermore, the order in which the garbage collector calls destructors for unreference objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members that are references to garbage collected objects, those references may no longer be valid. **This means that destructors cannot reference sub objects.**" (emphasis mine)
 Why can there be an "deplace" equivalent to emplace?
emplace is not responsible for allocation, it just does all the necessary things to place an object inside memory you provide (wherever it came from), and call the proper constructor. The opposite of emplace is destroy. This calls the destructor and resets the class to a "destroyed" state (so calling destroy on a class a second time will not call the destructor again).
 Everone says it's so easy not to use the GC in D yet I can't seem to
 find any real world examples ;/
The easiness of doing it is a judgment call. However, it is possible. I'm sure there are examples out there, but I'm not well versed in where to find them. -Steve
Jan 27 2016