Search code examples
c++classheap-memorymemcpy

Copy part of a class


I want to copy a part of a class to a buffer. I need this to make something that can look if there are changes in a class, and send it over the network to update the changes on the server.

I made a template class that can back-up and restore classes. Now I am making the "look for differences" function. I want that the user can define how big the memory blocks will be. This split the class in parts and takes less data to send.

The problem is that I can't copy a part of the class memory to the heap, I can't get the address correct. If I do "address of the class" + "0x04". Then I don't get the correct addres.

This is an exaple that I made:

testclass test1;
testclass test2;

test1.set(1,1);
test2.set(1,2);

cout << &test1 << " " << (&test1 + 0x04) << endl; //0018FF24 0018FF44

memcpy(&test2,&test1 + 0x04,4);

test2.echo(); //Wrong data!

The header:

class testclass
{
    int test,test2;

public:
    void set(int a, int b) {test = a, test2 = b;}
    void echo() {cout << test << " " << test2 << endl;}
};

I hope someone help me with this problem.

Thanks!


Solution

  • Basically, you can't muck around with pointers like that. You generally can't rely on the compiler to coincidentally put meaningful data there.

    If you want the address of members you should write &(test1.test2) not &test1+0x04 because even IF an int is 4 bytes and IF the compiler hasn't padded the structure and IF you or someone else hasn't changed the contents of the class, then &test1+0x04 really means "&test1 plus 4*sizeof(test) bytes", it's another way of reaching (&test1)[4] in terms of pointer-array-equivalence.

    Also, you can't memcpy over classes in general and expect meaningful results, unless they are POD.

    If you want to compare instances of a class, you should write a function which compares each of the members in turn.

    You can't write a general-purpose method for this because C++ is not a reflective language. That means you can't write code which magically knows the names and types of the members of a class.

    So, if you want to compare and patch data like this, you will need to do something like this:

    struct Foo {
        int a;
        int b;
    
        void export_differences (std :: ostream & o, const Foo & f) {
            if (a != f.a) o << "a " << f.a << " ";
            if (b != f.b) o << "b " << f.b << " ";
            o << ";";
        }
    
        void import_differences (std :: istream & i) {
            std :: string s;
            while (i >> s) {
                if (s == "a") i >> a;
                else if (s == "b") i >> b;
                else if (s == ";") break;
                else throw std :: runtime_error ("bad input");
            }
        }
    };
    

    You will have to write something like this for each class you want to patch.