How to implement a copy

bearophile bearophileHUGS at lycos.com
Thu Mar 18 11:41:14 PDT 2010


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


More information about the Digitalmars-d-learn mailing list