www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Disabled and enabled copy constructors and .dup

reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
If I have a `struct X` (container in my case) with disabled 
copying (postblit) and instead a .dup property, is it somehow 
possible, unsafe or not, to have `X` as a member of another 
`struct Y` with an enabled copy constructor which calls `X.dup`?
Oct 24
parent reply Biotronic <simen.kjaras gmail.com> writes:
On Tuesday, 24 October 2017 at 07:33:43 UTC, Per Nordlöw wrote:
 If I have a `struct X` (container in my case) with disabled 
 copying (postblit) and instead a .dup property, is it somehow 
 possible, unsafe or not, to have `X` as a member of another 
 `struct Y` with an enabled copy constructor which calls `X.dup`?
With the same approach outline in https://forum.dlang.org/post/nakguitssvjdclpgwhmk forum.dlang.org, it is indeed possible. In fact, simply using SuppressGC!X should enable it. Note however, that since the point of SuppressGC is to not call the object's destructor (and thus its name is poorly chosen by yours truly), you will need to do so explicitly. Updating the approach to only suppress postblits: struct SuppressPostblit(T) { // Disguise T as a humble array. private ubyte[T.sizeof] _payload; // Create from instance of T. this(T arg) { _payload = *cast(ubyte[T.sizeof]*)&arg; } // Or forward constructor arguments to T's constructor. static if (__traits(hasMember, T, "__ctor")) { this(Args...)(Args args) if (__traits(compiles, (Args e){__traits(getMember, T.init, "__ctor")(e);})) { __traits(getMember, get, "__ctor")(args); } } // Pretend to be a T. property ref T get() { return *cast(T*)_payload.ptr; } alias get this; static if (__traits(hasMember, T, "__dtor")) { ~this() { __traits(getMember, get, "__dtor")(); } } } -- Simen
Oct 24
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 24 October 2017 at 07:56:34 UTC, Biotronic wrote:
 struct SuppressPostblit(T)
 {
     // Disguise T as a humble array.
     private ubyte[T.sizeof] _payload;
 ...
A bit too hackish for my taste, but does the job still. Thanks.
Oct 24
parent Biotronic <simen.kjaras gmail.com> writes:
On Tuesday, 24 October 2017 at 11:37:42 UTC, Per Nordlöw wrote:
 On Tuesday, 24 October 2017 at 07:56:34 UTC, Biotronic wrote:
 struct SuppressPostblit(T)
 {
     // Disguise T as a humble array.
     private ubyte[T.sizeof] _payload;
 ...
A bit too hackish for my taste, but does the job still. Thanks.
Cleaned up and slightly less hackish (yeah, it bothered me too): enum SuppressOptions { destructor = 1, postblit = 2 } struct Suppress(T, SuppressOptions options) if (options != 0) { import std.traits : isCopyable; private enum suppressPostblit = (options & SuppressOptions.postblit) != 0; private enum suppressDestructor = (options & SuppressOptions.destructor) != 0; private enum postblitName = __traits(hasMember, T, "__xpostblit") ? "__xpostblit" : "__postblit"; // Disguise T as a humble array. private ubyte[T.sizeof] _payload; // Create from instance of T. this(T arg) { _payload = *cast(ubyte[T.sizeof]*)&arg; } // Or forward constructor arguments to T's constructor. static if (__traits(hasMember, T, "__ctor")) { this(Args...)(Args args) if (__traits(compiles, (Args e){__traits(getMember, T.init, "__ctor")(e);})) { __traits(getMember, get, "__ctor")(args); } } // Call dtor static if (!suppressDestructor) { ~this() { destroy(get); } } // Call postblit static if (!suppressPostblit) { static if (!isCopyable!T) { disable this(this); } else static if (__traits(hasMember, T, postblitName)) { this(this) { __traits(getMember, get, postblitName)(); } } } // Pretend to be a T. property ref T get() { return *cast(T*)_payload.ptr; } alias get this; } struct S1 { disable this(this); ~this() { throw new Exception("Don't touch my destructor!"); } } unittest { import std.exception; static assert(!__traits(compiles, (Suppress!S1 a) { auto b = a; })); static assert(__traits(compiles, (Suppress!(S1, SuppressOptions.postblit) a) { auto b = a; })); assertThrown({ Suppress!(S1, SuppressOptions.postblit) a; }()); assertNotThrown({ Suppress!(S1, SuppressOptions.postblit | SuppressOptions.destructor) a; }()); } -- Biotronic
Oct 24