On Sunday, 31 January 2016 at 20:20:52 UTC, Steven Schveighoffer wrote:
On 1/31/16 3:15 PM, Matt Elkins wrote:
On Sunday, 31 January 2016 at 20:11:07 UTC, Matt Elkins wrote:
On Sunday, 31 January 2016 at 20:10:03 UTC, Matt Elkins wrote:
On Sunday, 31 January 2016 at 20:07:26 UTC, Steven Schveighoffer wrote:
What is likely happening is that ptr is already collected, and you
are invalidly attempting to re-free it.

The GC can collect this memory even though there is still an
outstanding root-reachable pointer to it?

Or maybe it isn't root-reachable?

No, it is still present even if root-reachable:

[code]
unittest
{
     import std.algorithm;

     int* x;
     {
         auto map = new UniquePtr!int[1];
         auto uniqueX = UniquePtr!int(5);
         x = uniqueX.get();
         map[0] = move(uniqueX);
     }
}
[/code]

[output]
core.exception.InvalidMemoryOperationError@src\core\exception.d(679):
Invalid memory operation
----------------
Program exited with code 1
Made 632560 for this 18FD90
Disposing null for this 18FD70
Disposed null for this 18FD70
Disposing null for this 18FD90
Disposed null for this 18FD90
All unit tests have been run successfully.
Disposing 632560 for this 632550
[/output]

Oh, nevermind. This is actually simpler.

You can't do memory operations inside a destructor during collection. I forgot about that.

But the rule I stated is still in force.

-Steve
Honestly I don't quite understand why it would refree the ptr, but switching to malloc does seem to solve the problem.

struct UniquePtr(T) {
    import std.experimental.allocator;
    private T* ptr = null;
    IAllocator alloc;
@disable this(this); // This disables both copy construction and opAssign

    this(Args...)(auto ref Args args){
        import std.experimental.allocator.mallocator;
        alloc = allocatorObject(Mallocator.instance);
        ptr = alloc.make!T(args);
    }

    ~this() {
        alloc.dispose(ptr);
    }

    inout(T)* get() inout {
        return ptr;
    }

    // Move operations
    this(UniquePtr!T that) {
        this.ptr = that.ptr;
        that.ptr = null;
    }

ref UniquePtr!T opAssign(UniquePtr!T that) { // Notice no "ref" on "that"
        import std.algorithm.mutation;
swap(this.ptr, that.ptr); // We change it anyways, because it's a temporary
        return this;
    }
}

Reply via email to