Search code examples
c++g++copy-constructorcopy-assignment

Gcc uses memcpy for implicit copy-assignment operator instead of member-wise copy


following the c++ 11 standard i suppose that g++ implicitly uses a member-wise copy whenever an assignment between two objects is done. Surprisingly I noticed that contrary to the standard, g++ seems to invoke a memcpy sized at the actual size of the object. Here below a snippet of what I meant.

#include <stdio.h>

class Classe {
public:
    Classe(char m1 = 0, int m2 = 0) : membro1(m1), membro2(m2) {};

    void setMembro1(char m1)    {membro1 = m1;}
    void setMembro2(int m2)     {membro2 = m2;}
    char getMembro1() const     {return membro1;}
    int getMembro2() const      {return membro2;}
private:
    char membro1;
    int membro2;
};

Classe c;

void function() {
    c = Classe('a', 1);
}

int main() {
    char ciao[] = "HELLO!";
    printf("Ciao\n");
    function();
    printf("%d\n", sizeof(Classe));
}

At the end of execution I expect that the memory in which the "c" object is located is {0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, but apparently, next to the first location (which contains 0x61), some of the stack of the "function" function data are actually copied over, which is uncorrect, imho.

Do you have any idea of what's happening? Many thanks for your effort.


Solution

  • A C++ compiler can implement copying of the members in any manner it wants to as long as the result conforms to the C++ specs.

    In this case where the members are only fundamental types, and the underlying architecture doesn't get in the way, your C++ compiler could very well use memcpy() to perform the copying.

    On many implementations there will be padding in the memory layout between the char membro1 and char membro2 members in your object.

    The memory layout you see on your particular implementation will mean something like this:

    {0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}
     |     |      |     |     |__________________|
     |     padding|     |              |
     |           padding|            membro2
    membro1            padding
    

    The content of the memory in these 3 padding bytes are not specified, so any value you somehow observe there is of no consequence as far as C++ is concerned - even if a particular implementation happened to copy over some values in that padding area from the stack.