www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to implement a copy

reply Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
If I'm implementing a struct and want to provide for duplication, is there a
standard way to implement this?

Here's an example:

//-------------------------------

struct S {

    // members of the struct -- three integer values
    int a;
    int b;
    int c;

    // here's a copy constructor
    this(S s) {
        this.a = s.a;
        this.b = s.b;
        this.c = s.c;
    }

    // here's the dup property
    S dup() {
        S s;
        result.a = this.a;
        result.b = this.b;
        result.c = this.c;
        return s;
    }

    // here's opAssign for S
    void opAssign(S s) {
        this.a = s.a;
        this.b = s.b;
        this.c = s.c;
    }


} // end struct S

// and here's a copy function
S copy(S s) {
    S t;
    t.a = s.a;
    t.b = s.b;
    t.c = s.c;
    return t;
}

//-------------------------------

Which of these three calls is "better" (more efficient, more intuitive, more
consistent...)?

S s;    // the original struct

S t = s.dup;     // copied via dup
S u = S(s);      // copied via copy constructor
S v = s;           // copied via opAssign
S w = copy(s);  // copied via copy function

Or is this a distinction without a difference?

Paul
Mar 18 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Paul D. Anderson:
 Or is this a distinction without a difference?
For POD structs like this one I suggest to implement nothing, and just let the compiler copy the struct by itself. If the struct is not a POD then I like the dup property. Each of those other ways can be OK, according to the syntax you prefer to use :-) The free copy function is probably not necessary. If the struct has alignment "holes", like: struct Foo { double x; short y; } Then different copying methods are not the same. The holes are meant to be filled with bytes set to zero, but there can be situations where this can be false. So in those situations copying the whole memory block of a struct or copying just the members is not the same thing. The default D copy copies the whole block of memory. You can see the situation with this (D2 code, but I think it's the same in D1): import std.c.string: memset; import std.c.stdio: printf; struct Foo { double d; short s; static if (1) { void opAssign(Foo other) { this.d = other.d; this.s = other.s; } } } void showStruct(T)(T s) if (is(T == struct)) { foreach (b; cast(ubyte[T.sizeof])s) printf("%d ", b); printf("\n"); } void fillStruct(T)(ref T s, ubyte value) if (is(T == struct)) { memset(&s, value, T.sizeof); } void main() { Foo f, g; showStruct(f); showStruct(g); fillStruct(f, ubyte.min); fillStruct(g, ubyte.max); showStruct(f); showStruct(g); g = f; showStruct(f); showStruct(g); } /* Without opAssign: 0 0 0 0 0 0 252 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 252 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 lea ESI,-020h[EBP] lea EDI,-010h[EBP] movsd movsd movsd movsd ----------------------------- With opAssign: 0 0 0 0 0 0 252 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 252 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 Inside the Dmain_: ... lea EAX,-010h[EBP] call near ptr _D4bug23Foo8opAssignMFS4bug23FooZv ... _D4bug23Foo8opAssignMFS4bug23FooZv comdat L0: enter 4,0 mov -4[EBP],EAX cmp dword ptr -4[EBP],0 jne L2C push 9 push dword ptr _D4bug23Foo6__initZ[01Ch] push dword ptr _D4bug23Foo6__initZ[018h] push dword ptr _D4bug23Foo6__initZ[034h] push dword ptr _D4bug23Foo6__initZ[030h] call near ptr __d_assert_msg L2C: fld qword ptr 8[EBP] mov EAX,-4[EBP] fstp qword ptr [EAX] mov CX,010h[EBP] mov 8[EAX],CX leave ret 010h opAssign compiled with dmd -O -release: _D4bug23Foo8opAssignMFS4bug23FooZv comdat push EAX fld qword ptr 8[ESP] mov CX,010h[ESP] mov 8[EAX],CX fstp qword ptr [EAX] pop EAX ret 010h */ The performance too is not the same, the built-in copy is probably a little faster (you can see it from the asm too). If you want to be sure you can write a little benchmark. Bye, bearophile
Mar 18 2010
parent Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
bearophile Wrote:

 Paul D. Anderson:
 Or is this a distinction without a difference?
For POD structs like this one I suggest to implement nothing, and just let the compiler copy the struct by itself. If the struct is not a POD then I like the dup property. Each of those other ways can be OK, according to the syntax you prefer to use :-) The free copy function is probably not necessary.
Thanks for the help.
Mar 18 2010
prev sibling parent reply =?ISO-8859-1?Q?Pelle_M=E5nsson?= <pelle.mansson gmail.com> writes:
On 03/18/2010 05:43 PM, Paul D. Anderson wrote:
 If I'm implementing a struct and want to provide for duplication, is there a
standard way to implement this?

 Here's an example:

 //-------------------------------

 struct S {

      // members of the struct -- three integer values
      int a;
      int b;
      int c;

      // here's a copy constructor
      this(S s) {
          this.a = s.a;
          this.b = s.b;
          this.c = s.c;
      }

      // here's the dup property
      S dup() {
          S s;
          result.a = this.a;
          result.b = this.b;
          result.c = this.c;
          return s;
      }

      // here's opAssign for S
      void opAssign(S s) {
          this.a = s.a;
          this.b = s.b;
          this.c = s.c;
      }


 } // end struct S

 // and here's a copy function
 S copy(S s) {
      S t;
      t.a = s.a;
      t.b = s.b;
      t.c = s.c;
      return t;
 }

 //-------------------------------

 Which of these three calls is "better" (more efficient, more intuitive, more
consistent...)?

 S s;    // the original struct

 S t = s.dup;     // copied via dup
 S u = S(s);      // copied via copy constructor
 S v = s;           // copied via opAssign
 S w = copy(s);  // copied via copy function

 Or is this a distinction without a difference?

 Paul
this(this) is the copy constructor, I think. Try using that :)
Mar 19 2010
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
� wrote:

 this(this) is the copy constructor, I think.
this(this) is not the copy constructor. It is post-blit, which is useful for when corrections need to be done after the automatic blitting: http://digitalmars.com/d/2.0/struct.html#StructPostblit Ali
Mar 19 2010