Thread overview
struct postblit not called, but still destructed
Jan 19, 2014
Lemonfiend
Jan 19, 2014
Lemonfiend
Jan 19, 2014
Benjamin Thaut
Jan 19, 2014
monarch_dodra
Jan 19, 2014
monarch_dodra
Jan 20, 2014
Maxim Fomin
January 19, 2014
When a struct is passed to a function as argument, it is first copied and at the end destructed. But in the following code it is not copied, yet still destructed?

module main;

import std.stdio;

struct C
{
	A[] _objs;

	this(A[] objs...)
	{
		writeln(`  C this()`);
		_objs = objs;

		// A.this(this) is not called
		// yet A.~this IS called
	}
}

struct B
{
	A sup;
	alias sup this;

	this(A a)
	{
		writeln(count, ` B this()`);
		sup = a;
	}
}

struct A
{	
	static int count;

	this(int n)
	{
		count++;
		writeln(count, ` A this()`);
	}

	this(this)
	{
		count++;
		writeln(count, ` A this(this)`);
	}

	~this()
	{
		count--;
		writeln(count, ` A ~this()`);
	}
}

void main()
{
	A a = A(1);
	writeln(a.count == 1);

	B b = B(a);
	writeln(a.count == 2);

	C c = C(b);
	writeln(a.count == 3);
}
January 19, 2014
I just tried the new beta, and the issue remains.
January 19, 2014
Am 19.01.2014 18:48, schrieb Lemonfiend:
> import std.stdio;
>
> struct C
> {
>      A[] _objs;
>
>      this(A[] objs...)
>      {
>          writeln(`  C this()`);
>          _objs = objs;
>
>          // A.this(this) is not called
>          // yet A.~this IS called
>      }
> }
>
> struct B
> {
>      A sup;
>      alias sup this;
>
>      this(A a)
>      {
>          writeln(count, ` B this()`);
>          sup = a;
>      }
> }
>
> struct A
> {
>      static int count;
>
>      this(int n)
>      {
>          count++;
>          writeln(count, ` A this()`);
>      }
>
>      this(this)
>      {
>          count++;
>          writeln(count, ` A this(this)`);
>      }
>
>      ~this()
>      {
>          count--;
>          writeln(count, ` A ~this()`);
>      }
> }
>
> void main()
> {
>      A a = A(1);
>      writeln(a.count == 1);
>
>      B b = B(a);
>      writeln(a.count == 2);
>
>      C c = C(b);
>      writeln(a.count == 3);
> }


Yes this looks like a bug to me. Please file a bug report at https://d.puremagic.com/issues/

Kind Regards
Benjamin Thaut
January 19, 2014
On Sunday, 19 January 2014 at 19:24:23 UTC, Benjamin Thaut wrote:
> Yes this looks like a bug to me. Please file a bug report at https://d.puremagic.com/issues/
>
> Kind Regards
> Benjamin Thaut

Here is a reduced case:

//----
import std.stdio;

struct B
{
	A sup;

	this(A a)
	{
		writeln("Here");
		sup = a;
		writeln("There");
	}
}

struct A
{
	static int count;

	this(int n)
	{
		writeln("A.this()");
	}

	this(this)
	{
		writeln("A.this(this)");
	}

	~this()
	{
		writeln("A.~this()");
	}
}

void main()
{
	A a = A(1);

	writeln("Start");
	B b = B(a);
	writeln("End");
}
//----
A.this()
Start
A.this(this)
Here
A.this(this) //!!!
A.~this()    //!!!
There
A.~this()
End
A.~this()
A.~this()
//----

I think the behavior is not *strictly* incorrect: When you write:
sup = a;

it triggers a postblit of "a" into "sup". To do said postblit, you destroy sup. It's the way it works :/

Arguably, since it is initialization, we could avoid the destruction altogether, but it's not strictly *wrong*.

I'll file it as an ER, and try to get Kenji on it.
January 19, 2014
On Sunday, 19 January 2014 at 20:46:06 UTC, monarch_dodra wrote:
> I'll file it as an ER, and try to get Kenji on it.

https://d.puremagic.com/issues/show_bug.cgi?id=11952

As a workaround, it is usually recommended in the destructor to try to detect "initial state", and do nothing in such cases.

This is generally recommended anyways, since the .init state could mess up your count:

void main()
{
    //Scope
    {
        A a; //No increment count
    }//Destruction
    assert(A.count == 0); //Fails
}

I'd say disabling "this()" would help, but in this case, your example code still fails... I'll bump the report to bug because of this.
January 20, 2014
On Sunday, 19 January 2014 at 20:46:06 UTC, monarch_dodra wrote:
>
> I think the behavior is not *strictly* incorrect: When you write:
> sup = a;
>
> it triggers a postblit of "a" into "sup". To do said postblit, you destroy sup. It's the way it works :/
>
> Arguably, since it is initialization, we could avoid the destruction altogether, but it's not strictly *wrong*.
>
> I'll file it as an ER, and try to get Kenji on it.

It is rather bug than ER because recently there was work to recognize such cases (initial assignment in constructors) as initialization, not just assignment. However I am not sure here because these changes were not documented properly.