Search code examples
c++arrayspolymorphismconstantsvirtual

How to store constant 2D array in C++ class with virtual access?


I have to put few megabytes of data in two-dimensional arrays in C++ code (embed it in DLL), diffrent datasets for each subclass. I defined virtual accessor methods to access constants to specified subclass but it works only for primitives and 1D arrays, not for 2D arrays:

#include <stdio.h>

class SubClassHoldingData { // inheritance removed for short,compilable example
public:
    static int const notWorkingData[2][2];

    virtual int const** getNotWorkingData() { return (int const**)notWorkingData; } 
};

// simplified data set, about 200x200 in real application
const int SubClassHoldingData::notWorkingData[2][2] =  { { 1 , 2 } , { 3, 4 } };

int main( int argc , char** argv ) {
    SubClassHoldingData* holder = new SubClassHoldingData();
    const int** data = holder->getNotWorkingData();
    printf("data: %d" , data[1][1]); // !!! CRASHES APPLICATION !!!
}

I want to access data dynamiccaly (virtual) but with compile-time constant array like this:

DataHolder* holder = new FirstDataSetHolder();
const int** data = holder->get2DArray();

DataHolder* holder = new SecondDataSetHolder();
const int** data = holder->get2DArray(); 
// "data" contents DIFFERENT now, but compile-time constants!

How to achieve that?


Solution

  • If I understand the issue right, your problem is actually "how to return a pointer to pointer to some data that is in a 2D array".

    The problem with two layer pointers and 2D arrays is that a 2D array doesn't automatically make a pointer to pointer - they are two different things. A 2D array T arr[Y][X]; is a lump of memory of Y * X elements, where the offset to arr[a][b] is calculated as a * X + b.

    If we use the same arr[Y][X] in a dynamically allocated scenario, we would allocate a lump of memory Y long, and populate that with pointers to T that to a lump of memory X long each. So when we want to find arr[a][b], we first dig out pointer arr[a], then using that pointer add b elements to that.

    For your code to work, you would have to build that first array of pointers to each row in your array. Or return a pointer to an array with a fixed size for the [X] dimension, e.g.

    Edited:

     typedef int arr[X];
     ...
     class SomethingHolder 
     {
        ...
        arr* get2DArray();
        ...
     };
    
     const arr* data = holder->get2DArray(); 
    

    [I think it's technically possible to declare a function as returning a pointer to an array of integers, but I clearly didn't get the syntax right from my "obvious" type, and when trying to figure it out, I still couldn't get it right, so I gave up and used typedef of arr].

    Note that X must be a compile-time constant that is the same for the whole range.

    Another option is of course to have a holder->getData(x, y) that returns the actual data at [y][x] (or [x][y] depending on which way makes most sense).