Writing structured file in C++ I have a file with an specific format. It's divided in stripes of 1058816 bytes:


4096 bytes with only a 64 bit unsigned integer.
An array of 512 64 bit unsigned integer.
An array of 512 32 bit unsigned integer.
An array of 512 elements with 2048 bytes each one.


I have to read the file, change some values and write it again.

This is what I'm doing to work with it:

struct Segment {
        char bytes[2048];
};

struct Metadata {
        uint64_t serial;
};

class Stripe {
        uint8_t ptr[STRIPE_SIZE];

        Metadata *metadata;
        uint64_t *hash_array;
        uint32_t *size_array;
        Segment *segment_array;

        do_something(fstream_obj)
        {
                fstream_obj.read(ptr, STRIPE_SIZE);

                metadata = new(ptr) COSSMetadata;
                hash_array = new(ptr + METADATA_BYTES) uint64_t[ARRAY_SIZE];
                size_array = new(ptr + METADATA_BYTES + HASH_ARRAY_BYTES) uint32_t[ARRAY_SIZE];
                segment_array = new(ptr + METADATA_BYTES + HASH_ARRAY_BYTES + SIZE_ARRAY_BYTES) Segment[ARRAY_SIZE];

                // .... code to change the the values.....

                fstream_obj.write(ptr, STRIPE_SIZE);

        }
};


I have more experience with C. I'm not sure if this is the best to do what I want. I think that is faster, because I'm not doing any conversion and the information in ptr already is in the format of the structures. I want to hear opinios of more experience C++ coderes.
I'm not 100% sure how idiomatic this is, but since your data is so structured, it might be worth representing the entire structure as just that: a POD struct that contains the exact sizes and layout desired.

struct Metadata {
    uint64_t serial;
    char _padding_[METADATA_BYTES - 8];
};

struct Segment {
    char bytes[2048];
};

struct Stripe {
    Metadata metadata;
    uint64_t hash_array[512];
    uint32_t size_array[512];
    Segment segment_array[512];
};


(There is probably a better way of doing the padding.)

This means that the layout in memory is exactly the same as the layout on disk, and new Stripe will allocate the appropriate amount of memory with all the components contiguous as desired, without having to do the specific placement yourself. This means you can just allocate the structure, then file.read(stripe, sizeof(Stripe)) and file.write(stripe, sizeof(Stripe)) directly.

You could put a wrapper class around it:

class Stripe {
    Stripe_struct data;

    // methods...
}


Or just convert the original Stripe struct to a class itself.