Jump to page: 1 2
Thread overview
Copy Constructor
Jun 05, 2022
Salih Dincer
Jun 05, 2022
Alain De Vos
Jun 05, 2022
Salih Dincer
Jun 05, 2022
Alain De Vos
Jun 05, 2022
Ali Çehreli
Jun 05, 2022
Ali Çehreli
Jun 05, 2022
Ali Çehreli
Jun 05, 2022
Ali Çehreli
Jun 06, 2022
Ali Çehreli
Jun 05, 2022
Salih Dincer
Jun 05, 2022
Paul Backus
Jun 06, 2022
Salih Dincer
June 05, 2022

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:

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

June 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()

June 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:

>
  1. Foo one = Foo(1);
  2. Foo two = 2;
  3. [ Foo(3) ];

There is a fourth possibility:

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

June 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:

>

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:

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.

June 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

June 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 ?

June 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 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

June 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:
>> 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

June 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

June 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

« First   ‹ Prev
1 2