Let's say you have a struct that manages a malloc'd resource:
struct S(T)
{
private T* val;
@disable this(this);
this(T val) {
this.val = cast(T*)malloc(T.sizeof);
*this.val = val;
}
~this() {
free(val);
}
ref T get() { return *val; }
}
Now, if you just use an S!T on the stack, it works as expected.
But what happens if you destroy s
? If you do, then it will call the destructor a second time when the struct goes out of scope. However, destroy
will reinitialize the value with the .init
value.
What about destroy!false
? This doesn't initialize the value back to an .init state, and so leaves a dangling pointer in the above type.
This is a fuzzy area for me. I tend to always nullify any resource as soon as I destroy it, this way I don't accidentally screw it up later (old habit). But is that the correct expectation for a struct that has been destroyed? Is it reasonable to expect that once a struct is destroyed, it can never be used again (even to call the destructor)?
My thought is that, for a struct with a destructor:
a) the destructor should always be callable on its .init
value.
b) a struct that has been destroyed where its lifetime lives on should be overwritten with its '.init' value.
c) if destroyed without overwriting with .init
value, the program should make sure a second destructor call should not be allowed to happen in @safe code.
is c) reasonable? Do we need to deprecate @safe calls to destroy!false
for types that have destructors?
-Steve