www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Copy Constructor

reply Salih Dincer <salihdb hotmail.com> writes:
Hi,

Let be the structure Foo that wraps an int pointer. Let's setup 
Foo in 3 different ways:
 1. Foo one = Foo(1);
 2. Foo two = 2;
 3. [ Foo(3) ];
Pretty clean, right? So why it's not run copy-constructor in 3? Also, when we write to the screen with writeln(), why four times copy-constructors are running? **Playground:** https://run.dlang.io/is/qHvLJe **Source:** ```d struct Foo { int payload; this(int i) { this.payload = i; } this(ref return scope Foo that) { this = that; //cC = copyConstructor logger ~= format("cC(%s)", that.payload); } Foo opUnary(string op)() if(op == "++") { ++this.payload; return this; } int getter() { return payload; } alias getter this; } import std.stdio, std.format; string logger; void main() { Foo one = Foo(1), two = 2; int[] arr = [one, two, Foo(3)]; auto three = ++two;/* two.writeln(": 0x", &two.payload);//*/ //arr.writeln;/* foreach(ref i; arr) { i.writeln(": 0x", &i); }//*/ writeln("0x", &three.payload); logger.writeln; } // end with the logger! /* Print Outs: ================= 1: 0x7FD13D561000 2: 0x7FD13D561004 3: 0x7FD13D561008 0x7FFE6757E908 cC(1)cC(2)cC(3) */ ``` SDB 79
Jun 05 2022
next sibling parent reply Alain De Vos <devosalain ymail.com> writes:
I don't know the answer. But some questions come to my mind.
Does Foo(3) lives on the stack or the heap ?
There is also no assignment from Foo to Foo for Foo(3), there is 
a conversion.
And what happes with
Foo[3] arr = [one, two, Foo(3)];
Foo[]  arr=   [one, two, Foo(3)];
and
Foo x=Foo(3).dup()
Jun 05 2022
next sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 5 June 2022 at 18:43:19 UTC, Alain De Vos wrote:
 Does Foo(3) lives on the stack or the heap ?
Definitely not stack because that's what happens when the new operator is used. Article 14.3: https://dlang.org/spec/struct.html#intro SDB 79
Jun 05 2022
next sibling parent reply Alain De Vos <devosalain ymail.com> writes:
Could it be the copy constructor is only called during 
assignments (like C++).
And for one, two there is an explicit assignment.
But not for three where there is a conversion ?
Jun 05 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/5/22 14:04, Alain De Vos wrote:
 Could it be the copy constructor is only called during assignments (like
 C++).
The assignment operator is used during assignments both in C++ and D. A confusion comes from the fact that construction uses the same operator as assignment: a = b; // Assignment because 'a' already exists auto c = b; // Copy construction because 'c' is being constructed
 And for one, two there is an explicit assignment.
Actually, both are copy construction: Foo one = Foo(1), two = 2; You will never find me write code like because it's unclear. My version would be the following: Foo one = Foo(1); Foo two = 2; But even that is not my style because the first line repeats Foo and the second line hides the fact that there is construction. So, this is what I write in my programs: auto one = Foo(1); auto two = Foo(2);
 But not for three where there is a conversion ?
There are two "three"s in that code. The first one is construction (not copy): [one, two, Foo(3)] And the other one is copy construction: auto three = ++two; 'two' is first incremented and then a copy is made from 'two's new state. Ali
Jun 05 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/5/22 14:39, Ali Çehreli wrote:

 Actually, both are copy construction:
I am wrong there. I did confuse myself.
    Foo one = Foo(1), two = 2;
As my rewrite shows, they are both construction with an int:
    auto one = Foo(1);
    auto two = Foo(2);
Ali
Jun 05 2022
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/5/22 12:00, Salih Dincer wrote:
 On Sunday, 5 June 2022 at 18:43:19 UTC, Alain De Vos wrote:
 Does Foo(3) lives on the stack or the heap ?
I depends. I will respond to your other message.
 Definitely not stack because that's what happens when the new operator
 is used. Article 14.3: https://dlang.org/spec/struct.html#intro
I think you meant the other way. It is *not* on the stack if you use new. Ali
Jun 05 2022
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/5/22 11:43, Alain De Vos wrote:

 Does Foo(3) lives on the stack or the heap ?
It depends.
 there is a
 conversion.
Suche conversions are called "construction" in D.
 And what happes with
 Foo[3] arr = [one, two, Foo(3)];
Foo[3] is a static array. Static arrays are value types. Their elements normally do not live on heap: void foo() { Foo[3] arr; // On the stack } However, if Foo[3] were a member of something else class C { int i; Foo[3] arr; } and if an object of C is constructed on heap auto c = new C(); then the Foo[3] member will also live on the heap alongside 'i'. It could be the opposite: If the class object were emplaced on stack, then every member would we on the stack. As you see, "on the stack" really depends. Let's assume that your example is inside a function, i.e. the array is on the stack: void foo() { Foo[3] arr = [one, two, Foo(3)]; } Now all members of 'arr' on the stack. As 'one' and 'two' are lvalues, they are copied to arr[0] and arr[1]. But as Foo(3) is an rvalue, as Paul Backus said in the other message, that element is moved to arr[2]. So there are two copies and one move.
 Foo[]  arr=   [one, two, Foo(3)];
That one is different because Foo[] is a dynamic array that keeps its elements on the heap. That expression will allocate memory for at leasts 3 elements and to the same: Two copies and one move.
 and
 Foo x=Foo(3).dup()
If there were a dup() member function of Foo: struct Foo { Foo dup() { return Foo(this.payload); } } In that case, as the returned object is an rvalue, it would be moved to 'x'. The returned object could be an lvalue: struct Foo { Foo dup() { auto result = Foo(this.payload); // ... return result; } } In that case, the "named return value optimization" (NRVO) would be applied and the object would still be moved to 'x'. Ali
Jun 05 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/5/22 14:57, Ali Çehreli wrote:

 struct Foo {
    Foo dup() {
      auto result = Foo(this.payload);
      // ...
      return result;
    }
 }

 In that case, the "named return value optimization" (NRVO) would be
 applied and the object would still be moved to 'x'.
I am wrong there as well: Technically, NRVO (or RVO) does not move but constructs the object in the caller's stack frame. So, if the caller has the following code: auto z = existing.dup(); Then 'result' inside dup() is the same as caller's 'z'. Not 'result' but 'z' would be constructed in dup(). No move is performed and no value is actually returned. Ali
Jun 05 2022
prev sibling next sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 5 June 2022 at 15:45:17 UTC, Salih Dincer wrote:
 Hi,

 Let be the structure Foo that wraps an int pointer. Let's setup 
 Foo in 3 different ways:
 1. Foo one = Foo(1);
 2. Foo two = 2;
 3. [ Foo(3) ];
There is a fourth possibility: ```d int[] arr = [ one, two, Foo(3), *(new Foo(4)) ]; ``` The 1st, 2nd and 4th elements of array are copied, but the 3rd element is not. Could it have something to do with CTFE? https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe SDB 79
Jun 05 2022
parent Paul Backus <snarwin gmail.com> writes:
On Sunday, 5 June 2022 at 18:50:13 UTC, Salih Dincer wrote:
 On Sunday, 5 June 2022 at 15:45:17 UTC, Salih Dincer wrote:
 Hi,

 Let be the structure Foo that wraps an int pointer. Let's 
 setup Foo in 3 different ways:
 1. Foo one = Foo(1);
 2. Foo two = 2;
 3. [ Foo(3) ];
There is a fourth possibility: ```d int[] arr = [ one, two, Foo(3), *(new Foo(4)) ]; ``` The 1st, 2nd and 4th elements of array are copied, but the 3rd element is not. Could it have something to do with CTFE? https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe
Since the 3rd element is an rvalue, it is moved into the array rather than copied.
Jun 05 2022
prev sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 5 June 2022 at 15:45:17 UTC, Salih Dincer wrote:
 Also, when we write to the screen with writeln(), why four 
 times copy-constructors are running?

 **Playground:** https://run.dlang.io/is/qHvLJe
I solved the problem by implementing the `toString()` member function. I also had to use a helper `writeout()` as below: **struct Foo {** ```d string toString() {     return format("%s", payload);  } ``` **void main() {** ```d void writeout(T)(T text) {    text.toString.writeln;/*    import std.conv;    text.to!string.writeln;//*/ }  writeout(three); ``` Interestingly, even using `to!string` the copy-constructor works extra +4 times! I think there will be performance losses if `write()` is used unconsciously everywhere! Although this way, it kisses with ctor +1 times :) SDB 79
Jun 06 2022