c++runtime

Managing C++ objects in a buffer, considering the alignment and memory layout assumptions


I am storing objects in a buffer. Now I know that I cannot make assumptions about the memory layout of the object.

If I know the overall size of the object, is it acceptible to create a pointer to this memory and call functions on it?

e.g. say I have the following class:

[int,int,int,int,char,padding*3bytes,unsigned short int*]

1) if I know this class to be of size 24 and I know the address of where it starts in memory whilst it is not safe to assume the memory layout is it acceptible to cast this to a pointer and call functions on this object which access these members? (Does c++ know by some magic the correct position of a member?)

2) If this is not safe/ok, is there any other way other than using a constructor which takes all of the arguments and pulling each argument out of the buffer one at a time?

Edit: Changed title to make it more appropriate to what I am asking.


Solution

  • You can create a constructor that takes all the members and assigns them, then use placement new.

    class Foo
    {
        int a;int b;int c;int d;char e;unsigned short int*f;
    public:
        Foo(int A,int B,int C,int D,char E,unsigned short int*F) : a(A), b(B), c(C), d(D), e(E), f(F) {}
    };
    
    ...
    char *buf  = new char[sizeof(Foo)];   //pre-allocated buffer
    Foo *f = new (buf) Foo(a,b,c,d,e,f);
    

    This has the advantage that even the v-table will be generated correctly. Note, however, if you are using this for serialization, the unsigned short int pointer is not going to point at anything useful when you deserialize it, unless you are very careful to use some sort of method to convert pointers into offsets and then back again.

    Individual methods on a this pointer are statically linked and are simply a direct call to the function with this being the first parameter before the explicit parameters.

    Member variables are referenced using an offset from the this pointer. If an object is laid out like this:

    0: vtable
    4: a
    8: b
    12: c
    etc...
    

    a will be accessed by dereferencing this + 4 bytes.