Bug 5895 – Object.clear() doesn't work as expected for pointers to structs

Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
x86
OS
Linux
Creation time
2011-04-26T17:49:00Z
Last change time
2015-01-26T12:55:06Z
Assigned to
nobody
Creator
metalcaedes

Comments

Comment #0 by metalcaedes — 2011-04-26T17:49:02Z
AFAIK the main purpose of clear() is to call the destructor of it's argument and possibly invalidate it - this has been communicated in the d.D NG, however there's no official documentation on clear(). So it's a surprise that the following code compiles without any warnings but doesn't call Bar's destructor: struct Bar { ~this(){ writefln("bye"); } } Bar *b = new Bar(); clear(b); Instead it just does "b=b.init;" or something like that - I don't need clear for that. Especially because clear has been advertised as finally replacing delete I'd expect clear(b); to call b's destructor, even though b is just a pointer to a struct. Looking at clear()s implementation it's obvious what happens: b's type is neither a class, a struct nor an array, so it's set to b.init. So how can this be fixed? Some possibilities: 1. Dereference pointers (to structs or any pointers?) and clear the resulting type? (what about pointers to pointers?) 2. Disallow clear() for anything but classes and structs? Writing x = x.init; oneself isn't that hard, but this may not be bad for generic code that is supposed to work with both simple and custom types. 2.1 Dereference pointers to structs 2.2 Don't dereference pointers to structs but force the programmer to do it himself with an appropriate error 3. Disallow clear() only for pointers (but not for int etc)? A bit better for generic code I guess. Has the same sub-options as 2. 4. Keep clear() the way it is but introduce another function especially for structs and objects that does the dereferencing if necessary 5. Like 2. but introduce another function that behaves like the current clear() IMHO any change is possible because clear() isn't officially documented yet. But because it has often been mentioned in NG posts as something like delete for people who want to explicitly call the destructor, I'd prefer one of options 1. to 3. NG Thread discussing this a bit: http://lists.puremagic.com/pipermail/digitalmars-d/2011-April/101231.html and the following posts
Comment #1 by metalcaedes — 2011-05-01T21:37:12Z
An additional comment: Seems like clear() *is* documented - not in the online documentation but in TLDP on pages 187/188 (for classes) and 253/254 (for structs). It says: "You can invoke a struct object’s destructor explicitly by calling clear(obj).", and the last code-example included auto obj1 = S("first object"); No new there, so it's even correct with the current clear implementation. It doesn't mention that clear doesn't work with "auto obj = new S("blah");". And TLDP doesn't mention at all (at least on the pages the index lists for "clear") that clear can be used with simple types and even pointers, setting them to T.init. So I'd suggest to only allow clear() for (class-) Objects, structs and pointers to structs (in that case dereferencing the pointer and clearing the struct). If something like clear() that is so generic that it works for *any* type is needed, just add another function that does what clear() currently does.
Comment #2 by andy — 2015-01-25T01:41:04Z
This might be closeable. object.close() is deprecated and the compiler warns you should use destroy() instead. However: import std.stdio; struct Bar { ~this() { writeln("bye"); } } void main() { Bar *b = new Bar(); destroy(b); } Still doesnt call the destructor ... but that's because it needs to be called as: destroy(*b) There is form discussion here: http://forum.dlang.org/thread/[email protected] I wonder if there is any way the compiler can warn on: Bar *b = new Bar(); destroy(b); If so I think that should be a new bug, and this one closed.
Comment #3 by schveiguy — 2015-01-26T12:55:06Z
While the behavior may be unintuitive, the distinction is intended. Class references are actually the oddball behavior, but there is no way to separate the class data vs. the reference. In terms of replacing delete, destroy is not that, although it is part of it. I think in order for this to be "fixed" it needs to be in a DIP, or at least framed a different way.