Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 786
foxcub Avatar asked May 01 '26 15:05

foxcub


2 Answers

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;
}
like image 173
Matteo Italia Avatar answered May 03 '26 07:05

Matteo Italia


From your comment, it sounds like something like this might suffice:

#include <cstddef>
#include <array>
#include <algorithm>

template <typename T>
struct ArrayBase
{
  typedef T type;

  type & operator[](std::size_t i) { return buf[i]; }
  type const & operator[](std::size_t i) const { return buf[i]; }

protected:
  ArrayBase(type * p) : buf(p) { }

private:
  type * buf;
};

template <typename T, std::size_t N>
struct Array : ArrayBase<T>
{
  Array()
  : ArrayBase<T>(a.data())
  {
  }

  Array(Array const & rhs)
  : ArrayBase<T>(a.data())
  {
      std::copy(rhs.a.begin(), rhs.a.end(), a.begin());
  }

private:

  std::array<T, N> a;
};

Usage:

Array<int, 5> a5;
ArrayBase<int> & b = a5;
b[2] = 11;
Array<int, 5> a52 = a5;
a52[2] = 13;
like image 37
Kerrek SB Avatar answered May 03 '26 06:05

Kerrek SB



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!