Search code examples
c++memoryalignmentpadding

Accessing memory past the class


I have a peculiar problem. I want to create classes with variable length arrays in them. I don't want to allocate the arrays on the heap for the reasons of locality (the code slows down by a factor of 2 when I do). I don't want to use a virtual function because I don't want to pay for a function call. The following code works (on my compiler/platform), but with a caveat.

include <iostream>
include <boost/array.hpp>

struct Base
{
    Base(size_t s):
       size(s)                 {}
    int&        up(size_t i)   { return *(reinterpret_cast<int*>((&size) + 1) + i); }
    size_t      size;
};

template<size_t sz>
struct Derived: public Base
{
    boost::array<int, sz>       data;
    Derived(): Base(sz)         {}
};

int main()
{
    Derived<5> d5;
    d5.data[2] = 1234;
    Base* b = &d5;
    std::cout << b->up(2) << std::endl;
}

This is incredibly ugly; the reinterpret_cast<...> is a red flag. Moreover, the caveat is that this fails if I change size_t to, say, short unsigned (I guess the compiler pads the class).

So the question is: is there a way to make this portable? Is there a way to determine from Base where the first member variable will sit in its derived class?


Solution

  • Just an idea that came to my mind: let the Derived constructor store a pointer to its data inside a Base member.

    struct Base
    {
    protected:
        size_t size;
        int * array;
        Base(size_t s, int * arr):
          size(s), array(arr)
        { }
    
    public:
        int&   up(size_t i)   { return array[i]; }
        size_t getSize() { return size; }
    };
    
    template<size_t sz>
    struct Derived: public Base
    {
        std::array<int, sz> data;
    
        Derived():
          Base(sz, &data[0])
        { }
    };
    
    int main()
    {
        Derived<5> d5;
        d5.data[2] = 1234;
        Base* b = &d5;
        std::cout << b->up(2) << std::endl;
    }