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

Reply via email to