dimanche 27 novembre 2016

Accessing an object without storing a pointer to it in each instance

I have a situation similar to the following

struct Cell
{
  uint16_t x, y;
  // other fields

  Cell* right();
  Cell* above();
  ...
}

class Container
{
private:
  uint16_t width, height;
  Cell* data;

public:
  Container(uint16_t width, uint16_t height) : 
    width(width), height(height), data(new Cell[width*height])

  Cell* cellAt(uint16_t x, uint16_y) { &data[x*height + y]; }
};

Container* container;

Cell* Cell::right() { return container->cellAt(x+1, y); }
...

I trimmed down much of code (eg range checks and whatnot) just to show the design.

Basically this allow me everywhere in the code to access neighbour cells without passing by Container object directly (which would produce more verbose code and neighbours are accesses hundreds of times all around the code base). The solution works nicely and Container class is not even need to be known around the code, since Cell is enough.

This approach has a strong limit though: it allows only one instance of Container. Now I find myself in the situation of wanting multiple instances of Container, with independent Cell arrays but I don't want to change the structure of the code.

I'm thinking about a smart way to allow multiple Container, with the but

  • I want to keep the structure as it is
  • I absolutely don't want to store a Container* inside each Cell to avoid wasting a lot memory (we're talking in order of million of cells)
  • I want to keep it as much efficient as possible since these neighbour functions are used a lot

I was thinking about allocating width*height + 1 Cell instances and use the first instance to store a Container* in its memory, but the problem is how to compute the address of the first Cell considering that the total width/height are fields of Container itself (and not known by Cell).

So I guess I should store at least one pointer to Container* for each column (they are stored by column as shown by cellAt function for secondary reasons useless to the question). This would waste height*sizeof(Cell) bytes for each Container which could be quite a lot but I guess there's no way with with a single pointer.

So basically I could do something like:

Container** container = reinterpret_cast<Container**>(&data[0])
*container = this;

And then retrieve the object. Of course this is a dirty hack which could give problems on architecture which doesn't support unaligned accesses if sizeof(Cell) % alignof(void*) != 0.

Are there smarter solutions which I'm missing?

Aucun commentaire:

Enregistrer un commentaire