digitalmars.D.learn - Reference counting questions
- Johannes Pfau (38/38) Jul 22 2011 I have some problems understanding the reference counting code in
- Jesse Phillips (8/8) Jul 22 2011 I don't really think stdio is the place to see modern D ref counting. Th...
- Johannes Pfau (23/31) Jul 23 2011 Thanks, I think I understand how to use RefCounted now.
- Johannes Pfau (11/19) Jul 23 2011 Totally overlooked a 'small' problem with RefCounted: It can't work for
- Andrej Mitrovic (31/31) Jul 24 2011 I'm don't understand why this code calls the dtor before it calls the ct...
- Johannes Pfau (11/43) Jul 25 2011 Strange, I can confirm this behavior and it seems to happen all the
I have some problems understanding the reference counting code in std.stdio. The reduced code my questions refer to is here: https://gist.github.com/1099229 (ignore the not-working struct default constructor, that's just to simplify the code) in line 5: why is 'refs' initialized to 'uint.max / 2'? in line 40: what does 'swap(p, rhs.p);' do? Does it decrease the reference count of the 'original' File and increase the reference count of the 'new' File? Or does the compiler automatically call the copy constructor and the destructor when it calls opAssign? There was some discussion some time ago whether atomic ops have to be used for ref-counting (something about finalizers of heap allocated structs?). What happened to that issue? How's ref-counting supposed to behave with global variables? -------------------------- module test; File file; void main() { file = File("/blah"); test(); } void test() { file.read(); //<-- will/should this work? } -------------------------- What happens if a ref-counted struct is used as a member in a class? Will the GC decrease the struct's reference count when the class gets collected? Is it possible to add explicit de-referencing to allow a global struct / struct in class to be manually dereferenced? Is detach meant to do that? Would this naive implementation work? https://gist.github.com/1099360 Maybe with the detach addition the copy-ctor and opAssign should throw on p == null? So that copies of a detached object cannot be made? -- Johannes Pfau
Jul 22 2011
I don't really think stdio is the place to see modern D ref counting. The container class has an Array which is built to use RefCounted. I had tried my and at explaining how to use it: http://stackoverflow.com/ questions/4632355/making-a-reference-counted-object-in-d-using- I'm not really sure if all the details have been worked out. Hopefully I explained it correctly and that it gives you an idea of how to make ref counting work.
Jul 22 2011
Jesse Phillips wrote:I don't really think stdio is the place to see modern D ref counting. The container class has an Array which is built to use RefCounted. I had tried my and at explaining how to use it: http://stackoverflow.com/ questions/4632355/making-a-reference-counted-object-in-d-using- I'm not really sure if all the details have been worked out. Hopefully I explained it correctly and that it gives you an idea of how to make ref counting work.Thanks, I think I understand how to use RefCounted now. But it still leaves this issue: Is it possible to add explicit de-referencing to allow a global struct / struct in class to be manually dereferenced? And it adds a new one: RefCounted calls addRange https://github.com/D-Programming-Language/phobos/blob/master/std/typecons.d#L2304 if the _store size is >= size_t (In fact, as _store already has a size_t for count, addRange will always get called?). This means even if I only want RefCounting for a simple C handle, addRange will be called. I don't understand the use of malloc & free in RefCounted. If addRange is called anyway, why not just use GC.malloc and GC.free? One more thing: The removeRange call uses a different condition: if (hasIndirections!T && RefCounted._store) GC.removeRange(RefCounted._store); if (sz >= size_t.sizeof && p.ptr) GC.addRange(p.ptr, sz); Now say, I store a single byte, wouldn't addRange get called but removeRange not? -- Johannes Pfau
Jul 23 2011
Jesse Phillips wrote:I don't really think stdio is the place to see modern D ref counting. The container class has an Array which is built to use RefCounted. I had tried my and at explaining how to use it: http://stackoverflow.com/ questions/4632355/making-a-reference-counted-object-in-d-using- I'm not really sure if all the details have been worked out. Hopefully I explained it correctly and that it gives you an idea of how to make ref counting work.Totally overlooked a 'small' problem with RefCounted: It can't work for cairoD ;-) In cairo the c handle is already reference-counted, so I should use cairo_*_[de]reference(ptr) instead of my own counter, but that can't be done with RefCounted. I think I'll have to adapt the RefCounted implementation for cairoD. But I can still use RefCounted in other projects. BTW: RefCounted also uses std.algorithm.swap in it's opAssign. Still wondering what that's supposed to do. -- Johannes Pfau
Jul 23 2011
I'm don't understand why this code calls the dtor before it calls the ctor: import std.stdio; import std.typecons; void main() { auto wrap1 = Wrapper(1); } void free(ref int _payload) { writeln("dealloc"); _payload = 0; } struct Wrapper { struct Payload { int _payload; this(int h) { writeln("alloc"); _payload = h; } ~this() { free(_payload); } this(this) { assert(false); } void opAssign(Wrapper.Payload rhs) { assert(false); } } private alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data; private Data _data; this(int h) { _data = Data(h); } } prints: dealloc alloc dealloc What's with the first dtor call?
Jul 24 2011
Andrej Mitrovic wrote:I'm don't understand why this code calls the dtor before it calls the ctor: import std.stdio; import std.typecons; void main() { auto wrap1 = Wrapper(1); } void free(ref int _payload) { writeln("dealloc"); _payload = 0; } struct Wrapper { struct Payload { int _payload; this(int h) { writeln("alloc"); _payload = h; } ~this() { free(_payload); } this(this) { assert(false); } void opAssign(Wrapper.Payload rhs) { assert(false); } } private alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data; private Data _data; this(int h) { _data = Data(h); } } prints: dealloc alloc dealloc What's with the first dtor call?Strange, I can confirm this behavior and it seems to happen all the time when using RefCounted. I guess this was never an issue for the RefCounted code in phobos (for example std.container.Array) as RefCounted was only used to manage memory, not handles from C libraries. free simply does nothing if called with a null pointer, so this problem never showed up. As a workaround, check your handle against null in the destructor before calling the function to close the handle. -- Johannes Pfau
Jul 25 2011