www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - 'Double free' even with disabled this(this)

reply "Maurice" <m-ou.se m-ou.se> writes:
Hey,

I'm trying to use a struct for RAII (like C++'s unique_ptr), so i 
 disabled this(this). However, it's still getting copied somehow:

struct A {
	int some_resource = 0;
	~this() { if (some_resource) writeln("Freeing resource."); }
	 disable this(this); // Prevent copying
}

struct B {
	A a;
	alias a this;
}

void main() {
	B b;
	b.some_resource = 100;
	A a = move(b);
}

The above code prints 'Freeing resource.' twice!

See it in action on http://dpaste.dzfl.pl/6461df03

I guess the first one is from the temporary B that move(b) gives. 
However, that temporary should be moved into a and then left in 
B.init state, but that doesn't happen.

Is this a bug?
Oct 25 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 25 October 2013 at 18:24:51 UTC, Maurice wrote:
 Hey,

 I'm trying to use a struct for RAII (like C++'s unique_ptr), so 
 i  disabled this(this). However, it's still getting copied 
 somehow:

 struct A {
 	int some_resource = 0;
 	~this() { if (some_resource) writeln("Freeing resource."); }
 	 disable this(this); // Prevent copying
 }

 struct B {
 	A a;
 	alias a this;
 }

 void main() {
 	B b;
 	b.some_resource = 100;
 	A a = move(b);
 }

 The above code prints 'Freeing resource.' twice!

 See it in action on http://dpaste.dzfl.pl/6461df03

 I guess the first one is from the temporary B that move(b) 
 gives. However, that temporary should be moved into a and then 
 left in B.init state, but that doesn't happen.

 Is this a bug?
Yes, it seems to be a bug related to alias this. If we remove the alias this, and type the call explicitly, then we get this: //---- struct B { A a; //alias a this; //Let's do things explicitly. } void main() { B b; b.a.some_resource = 100; A a = move(b).a; } //---- Error: struct main.A is not copyable because it is annotated with disable //---- I don't think you should get a *different* behavior with an explicit call, no matter what said behavior is. You should file it in buzilla: http://d.puremagic.com/issues/ In this case, not compiling is the correct behavior I think: If have an B rvalue you can move, then doesn't mean you can selectivelly move its members (eg A). Think of it in terms of C++ like struct inheritance: If A is a base of B, you can't move a B into an A. The issue here is you are trying to move a B into an A, and that *can't* work. However, you can move the b.a into the a, that's fine. This does what you want: //---- void main() { B b; b.a.some_resource = 100; A a = move(b.a); //Move b.a, *NOT* b itself } //---- Freeing resource. //(Once) //----
Oct 25 2013