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
Permalink
Reply