Is it possible to avoid call to destructor for structs?

Biotronic simen.kjaras at gmail.com
Sun Sep 24 19:24:53 UTC 2017


On Sunday, 24 September 2017 at 18:46:15 UTC, Haridas wrote:
> Also consider the following code. Please let me know if I am 
> doing the right thing for dynamic arrays. My hack seems to have 
> the desired effect on shutting down the destructor. Is this 
> hack legal use of D? Can you please guide me if/how it can be 
> achieved for std.container.Array?
>
> // >>>>
> import std.stdio;
>
> struct Bar {
>   ~this() {
>     writeln("~Bar");
>   }
> }
>
> void main() {
>   {				// dynamic array
>     Bar[] bars;
>     bars.length = 4;
>     void* tmp = bars.ptr;
>     delete(tmp);
>     bars.length = 0;
>   }
>   {				// std.container.Array
>     import std.container: Array;
>     Array!Bar bars;
>     bars.length = 6;
>     // does not seem to work
>     void* tmp = &(bars[0]);
>     delete(tmp);
>     bars.length = 0;
>   }
> }

Since you're deleting the memory the dynamic array is pointing 
to, what you're doing is potentially unsafe - if anyone touches 
that memory after it's been deleted, nasal demons may follow.

What you want is something like this:

import std.stdio;

struct Bar
{
     this(int n) {}

     ~this()
     {
         writeln("~Bar");
     }
}

struct SuppressGC(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;
}

void useBar(ref Bar b) {}

unittest
{
     // Construct from instance.
     //This creates a temporary on the stack, and its destructor 
will be called.
     SuppressGC!Bar a = Bar(3);

     // Or by forwarding constructor arguments.
     // This constructs in-place inside SuppressGC, and no 
destructor will be called.
     auto b = SuppressGC!Bar(3);

     SuppressGC!Bar[] arr;
     arr.length = 3;

     // Another stack temporary. Destructor will be called.
     arr[0] = Bar(5);

     // No temp
     arr[1] = SuppressGC!Bar(5);

     // It even pretends to be the wrapped struct:
     useBar(b);
}

In general, of course, this is a bad idea - there's probably a 
reason that destructor does the thing it's doing. If you're sure 
skipping it is what you want, go ahead.

--
   Biotronic


More information about the Digitalmars-d-learn mailing list