1

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?

Piotr Müller
  • 4,845
  • 3
  • 45
  • 79
  • 1
    Everything would be way easier if you used `std::array`. – juanchopanza May 07 '13 at 07:46
  • Will it be a compile time constant, or can be loaded at application startup from constants and hold for rest of application life? Can you post a example? – Piotr Müller May 07 '13 at 07:50
  • looks a lot like you are doing "C with classes". `` is not part of C++, the corresponding legacy header is ``, then you can (and should) use `std::array` or `std::vector` instead of the multidimensional arrays. For that matter, maybe [this SO question](http://stackoverflow.com/questions/14275773/allocate-memory-for-2d-array-with-c-new/) will be of help for you. And last but not least, [`new` is pretty old now](http://stackoverflow.com/questions/6500313/why-should-new-be-used-as-little-as-possible). – Arne Mertz May 07 '13 at 07:57
  • But remeber that I want to compile-time constants. I prefer loading 10MB DLL with compile-time constants rather than loading 10MB DLL with compile-time constants for initialise another dynamically allocated 10MB (20MB memory usage for 10MB of real data) – Piotr Müller May 07 '13 at 07:59

2 Answers2

1

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).

Mats Petersson
  • 119,687
  • 13
  • 121
  • 204
  • This solution looks good, I know all dimensions before compilation. But this doesn't compile: `const int(*)[2] data = holder->getNotWorkingData();` – Piotr Müller May 07 '13 at 08:02
  • Even `const int[2][2] data` dosen't compile: "expected unqualified-id before '[' token" – Piotr Müller May 07 '13 at 08:10
  • Ok thanks, this solution works. This is a little bit problematic to create multiple typedefs for all my sizes, but i will post another question. – Piotr Müller May 07 '13 at 08:19
  • You may be able to use templates or something for that - or, like I said, use a `getData(x, y)` type function - if the code is written correctly, this can be inlined and fetch the correct data as quickly as anything else. – Mats Petersson May 07 '13 at 08:22
  • I'd use the `typedef` too, but if I'm not mistaken, the declarations without the `typedef` would be `int (*get2DArray() const)[2];` (with definition `int (*SomethingHolder::get2DArray() const)[2] { ... }`) and use `int const (*data)[2] = holder->get2DArray();`. Which is, I think, a very strong argument in favor of the `typedef`. – James Kanze May 07 '13 at 09:35
  • Thanks James, I probably wouldn't have come up with that syntax in a 100 hours, had I had enough motivation to spend that long... – Mats Petersson May 07 '13 at 09:37
0

Mats Petersson 's resolution is quite right.But if You want to use the array form.It's also have a method:

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

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

typedef int  (*SecondDemPtr)[2][2] ;  //this type is a pointer to your array

And:

SubClassHoldingData* holder = new SubClassHoldingData();
SecondDemPtr data = (SecondDemPtr)(holder->getNotWorkingData());
printf("data: %d" , (*data)[1][1]); // !!! CRASHES APPLICATION !!!

This method is not a good idear,but can transform between array and pointer of array.

MIKU_LINK
  • 182
  • 8