digitalmars.D.learn - Copy Constructor
- Salih Dincer (57/60) Jun 05 2022 Hi,
- Alain De Vos (9/9) Jun 05 2022 I don't know the answer. But some questions come to my mind.
- Salih Dincer (5/6) Jun 05 2022 Definitely not stack because that's what happens when the new
- Alain De Vos (4/4) Jun 05 2022 Could it be the copy constructor is only called during
- =?UTF-8?Q?Ali_=c3=87ehreli?= (24/28) Jun 05 2022 The assignment operator is used during assignments both in C++ and D.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/8) Jun 05 2022 As my rewrite shows, they are both construction with an int:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/8) Jun 05 2022 I think you meant the other way. It is *not* on the stack if you use new...
- =?UTF-8?Q?Ali_=c3=87ehreli?= (49/57) Jun 05 2022 Suche conversions are called "construction" in D.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (9/18) Jun 05 2022 I am wrong there as well: Technically, NRVO (or RVO) does not move but
- Salih Dincer (9/15) Jun 05 2022 There is a fourth possibility:
- Paul Backus (3/18) Jun 05 2022 Since the 3rd element is an rvalue, it is moved into the array
- Salih Dincer (23/26) Jun 06 2022 I solved the problem by implementing the `toString()` member
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
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
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
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
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 constructedAnd 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
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
On 6/5/22 12:00, Salih Dincer wrote:On Sunday, 5 June 2022 at 18:43:19 UTC, Alain De Vos wrote:I depends. I will respond to your other message.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#introI think you meant the other way. It is *not* on the stack if you use new. Ali
Jun 05 2022
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
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
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: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 791. Foo one = Foo(1); 2. Foo two = 2; 3. [ Foo(3) ];
Jun 05 2022
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:Since the 3rd element is an rvalue, it is moved into the array rather than copied.Hi, Let be the structure Foo that wraps an int pointer. Let's setup Foo in 3 different ways: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-ctfe1. Foo one = Foo(1); 2. Foo two = 2; 3. [ Foo(3) ];
Jun 05 2022
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/qHvLJeI 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