www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unexpected copy constructor behavior

reply psycha0s <box mail.com> writes:
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
Jul 09 2020
next sibling parent psycha0s <box mail.com> writes:
I just didn't expect that the address of a "this" reference may 
change.
Jul 09 2020
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Jul 09 2020
parent reply psycha0s <bix gmail.com> writes:
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.
Jul 10 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
Jul 10 2020