Re: Ownership semantics

2016-01-31 Thread Matt Elkins via Digitalmars-d-learn

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?


Re: Ownership semantics

2016-01-31 Thread Matt Elkins via Digitalmars-d-learn
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?


Re: Ownership semantics

2016-01-31 Thread maik klein via Digitalmars-d-learn
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;
}
}



Re: Ownership semantics

2016-01-31 Thread Matt Elkins via Digitalmars-d-learn
On Sunday, 31 January 2016 at 20:20:52 UTC, Steven Schveighoffer 
wrote:

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


So this implies that the UniquePtr implementation originally 
posted might work with malloc/free calls, or some other non-GC 
allocator...of course, in that case one could just use 
std.typecons.Unique.


Re: Ownership semantics

2016-01-31 Thread Matt Elkins via Digitalmars-d-learn

On Sunday, 31 January 2016 at 19:34:43 UTC, maik klein wrote:
I recently asked a question about ownership semantics in D 
https://stackoverflow.com/questions/35115702/how-do-i-express-ownership-semantics-in-d


But a few minutes ago I found an answer on SO that could 
potentially explain a lot.


http://stackoverflow.com/a/35114945/944430

Sadly it has some pseudo code in it so I implemented it with 
std.experimental.allocator


struct UniquePtr(T) {
import std.experimental.allocator;
private T* ptr = null;

@disable this(this); // This disables both copy 
construction and opAssign


this(Args...)(auto ref Args args){
ptr = theAllocator.make!T(args);
}

~this() {
theAllocator.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;
}
}

Is this code correct? One problem that I have is

UniquePtr!int[int] map;

will result in a memory exception and I have no idea why.


Interesting. It is something in the dispose, because I changed 
the destructor to:


[code]
~this()
{
writeln("Disposing ", ptr, " for this ", );
theAllocator.dispose(ptr);
writeln("Disposed ", ptr, " for this ", );
}
[/code]

And I only get the disposing line, not the disposed.

I tried taking my ResourceHandle struct that I pasted to you in 
the other thread earlier and doing the same operation with it (I 
had to change a const to inout and remove an extraneous 'in' 
marker to make it compile):


[code]
alias RH = ResourceHandle!(int*, (int* ptr) 
{theAllocator.dispose(ptr);});

RH[int] otherMap;
otherMap[3] = RH(theAllocator.make!int(5));
[/code]

and I get the same invalid memory operation. With either class, I 
avoid the error if I use a stack member or a static array, but 
with the associative array or just a dynamic array I get the 
problem.


To see it in a dynamic array:
[code]
auto map = new UniquePtr!int[1];
map[0] = UniquePtr!int(5);
[/code]

Not sure what it is...still playing with it.


Re: Ownership semantics

2016-01-31 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/31/16 2:34 PM, maik klein wrote:

I recently asked a question about ownership semantics in D
https://stackoverflow.com/questions/35115702/how-do-i-express-ownership-semantics-in-d


But a few minutes ago I found an answer on SO that could potentially
explain a lot.

http://stackoverflow.com/a/35114945/944430

Sadly it has some pseudo code in it so I implemented it with
std.experimental.allocator

struct UniquePtr(T) {
 import std.experimental.allocator;
 private T* ptr = null;

 @disable this(this); // This disables both copy construction and
opAssign

 this(Args...)(auto ref Args args){
 ptr = theAllocator.make!T(args);
 }

 ~this() {
 theAllocator.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;
 }
}

Is this code correct? One problem that I have is

UniquePtr!int[int] map;

will result in a memory exception and I have no idea why.


The default allocator is the GC.

For memory that is destroyed by the GC, you cannot access to 
GC-allocated members in the destructor (destruction order is not 
guaranteed by the GC). Therefore, you should not 'dispose(ptr)' in the dtor.


What is likely happening is that ptr is already collected, and you are 
invalidly attempting to re-free it.


I'm pretty sure there is no facility in the allocator to give you enough 
information to properly implement this. In other words, for non-GC 
allocators, you *should* dispose the ptr. But how can you tell?


-Steve


Re: Ownership semantics

2016-01-31 Thread Steven Schveighoffer via Digitalmars-d-learn

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


Re: Ownership semantics

2016-01-31 Thread Matt Elkins via Digitalmars-d-learn

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]


Ownership semantics

2016-01-31 Thread maik klein via Digitalmars-d-learn
I recently asked a question about ownership semantics in D 
https://stackoverflow.com/questions/35115702/how-do-i-express-ownership-semantics-in-d


But a few minutes ago I found an answer on SO that could 
potentially explain a lot.


http://stackoverflow.com/a/35114945/944430

Sadly it has some pseudo code in it so I implemented it with 
std.experimental.allocator


struct UniquePtr(T) {
import std.experimental.allocator;
private T* ptr = null;

@disable this(this); // This disables both copy construction 
and opAssign


this(Args...)(auto ref Args args){
ptr = theAllocator.make!T(args);
}

~this() {
theAllocator.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;
}
}

Is this code correct? One problem that I have is

UniquePtr!int[int] map;

will result in a memory exception and I have no idea why.