Thread overview
Unexpected copy constructor behavior
Jul 09, 2020
psycha0s
Jul 09, 2020
psycha0s
Jul 10, 2020
psycha0s
July 09, 2020
I was learning copy constructors and got a really weird result. It looks like a copy constructor and a destuctor of two unknown objects are called. Could somebody please explain it to me?

>import std.stdio;
>
>struct Foo {
>	int value;
>
>	this(int n)
>	{
>		value = n;
>		writeln("constuctor ", &this);
>	}
>
>	~this()
>	{
>		writeln("destuctor ", &this);
>	}
>
>	this(ref return scope Foo other)
>	{
>		value = other.value;
>		writeln("copy constuctor ", &this);
>	}
>}
>
>void main()
>{
>	writeln("begin");
>	auto foo1 = Foo(1);
>	auto foo2 = foo1;
>	writeln("---");
>	foo2 = foo1;
>	writeln("===");
>	writeln("end");
>}

The output:

>begin
>constuctor A3D3EFF860
>copy constuctor A3D3EFF864
>---
>copy constuctor A3D3EFF880     // <--
>destuctor A3D3EFF808           // <--
>===
>end
>destuctor A3D3EFF864
>destuctor A3D3EFF860

July 09, 2020
I just didn't expect that the address of a "this" reference may change.
July 09, 2020
On 7/9/20 6:08 PM, psycha0s wrote:
> import std.stdio;
> 
> struct Foo {
>      int value;
> 
>      this(int n)
>      {
>          value = n;
>          writeln("constuctor ", &this);
>      }
> 
>      ~this()
>      {
>          writeln("destuctor ", &this);
>      }
> 
>      this(ref return scope Foo other)
>      {
>          value = other.value;
>          writeln("copy constuctor ", &this);
>      }
> }
> 
> void main()
> {
>      writeln("begin");
>      auto foo1 = Foo(1);
>      auto foo2 = foo1;
>      writeln("---");
>      foo2 = foo1;
>      writeln("===");
>      writeln("end");
> }

Looking at the generated AST, it's because the compiler is adding an auto-generated opAssign, which accepts a Foo by value. It is that object that is being created and destroyed. Your objects aren't moving.

Here is what AST looks like for main:

void main()
{
	writeln("begin");
	Foo foo1 = foo1 = 0 , foo1.this(1);
	try
	{
		Foo foo2 = foo2 = 0 , foo2.this(foo1);
		try
		{
			writeln("---");
			foo2.opAssign(((Foo __copytmp434 = __copytmp434 = 0 , __copytmp434.this(foo1);) , __copytmp434));
			writeln("===");
			writeln("end");
		}
		finally
			foo2.~this();
	}
	finally
		foo1.~this();
	return 0;
}

-Steve
July 10, 2020
On Thursday, 9 July 2020 at 22:18:59 UTC, Steven Schveighoffer wrote:
> Looking at the generated AST, it's because the compiler is adding an auto-generated opAssign, which accepts a Foo by value. It is that object that is being created and destroyed.

Is there a reason the autogenerated opAssign accepts its argument by value? Honestly, it looks like a premature pessimisation to me.
July 10, 2020
On 7/10/20 3:31 AM, psycha0s wrote:
> On Thursday, 9 July 2020 at 22:18:59 UTC, Steven Schveighoffer wrote:
>> Looking at the generated AST, it's because the compiler is adding an auto-generated opAssign, which accepts a Foo by value. It is that object that is being created and destroyed.
> 
> Is there a reason the autogenerated opAssign accepts its argument by value? Honestly, it looks like a premature pessimisation to me.

If it accepts the value by ref, then it will not bind to rvalues. Accepting by value accepts anything.

-Steve