T.init, struct destructors and invariants - should they be called?
Simen Kjærås
simen.kjaras at gmail.com
Fri Jul 6 12:10:58 UTC 2018
On Friday, 6 July 2018 at 10:44:09 UTC, FeepingCreature wrote:
> Why is this a problem? ("Just don't use S.init!")
>
> Well, for one it makes Nullable!S impossible. Nullable, if it
> is to be @nogc, *necessarily* has to construct an S.init struct
> member.
The rest looks sensible to me, but I have to say this is
bollocks. This Nullable never has to construct an S.init:
struct Nullable(T) {
ubyte[T.sizeof] _payload;
bool _hasValue;
@property @trusted
ref T value() {
assert(_hasValue);
return *cast(T*)_payload.ptr;
}
@property @trusted
void value(T val) {
cleanup();
_hasValue = true;
_payload = *cast(typeof(_payload)*)&val;
}
@property
void value(typeof(null)) {
cleanup();
_hasValue = false;
}
@trusted
private void cleanup() {
if (!_hasValue) return;
destroy(*cast(T*)_payload.ptr);
_hasValue = false;
}
this(T val) {
value = val;
}
~this() {
cleanup();
}
this(typeof(null) val) {
value = val;
}
void opAssign(T val) {
value = val;
}
void opAssign(typeof(null) val) {
value = val;
}
}
struct S
{
Object obj;
invariant
{
assert(this.obj !is null);
}
@disable this();
@safe
this(Object obj)
{
this.obj = obj;
}
@safe ~this() {}
}
@safe unittest {
Nullable!S a; // Look ma, no assert!
}
Not only do I think it's unnecessary for Nullable to declare a T
field, I think it's a bug if it does. The destructor problem you
point out is one of the key reasons for this.
--
Simen
More information about the Digitalmars-d
mailing list