views:

85

answers:

3

I have something I need a 2D array for, but for better cache performance, I'd rather have it actually be a normal array. Here's the idea I had but I don't know if it's a terrible idea:

const int XWIDTH = 10, YWIDTH = 10;
int main(){
    int * tempInts = new int[XWIDTH * YWIDTH];
    int ** ints = new int*[XWIDTH];
    for(int i=0; i<XWIDTH; i++){
        ints[i] = &tempInts[i*YWIDTH];
    }
    // do things with ints
    delete[] ints[0];
    delete[] ints;
    return 0;
}

So the idea is that instead of newing a bunch of arrays (and having them placed in different places in memory), I just point to an array I made all at once.

The reason for the delete[] (int*) ints; is because I'm actually doing this in a class and it would save [trivial amounts of] memory to not save the original pointer.

Just wondering if there's any reasons this is a horrible idea. Or if there's an easier/better way. The goal is to be able to access the array as ints[x][y] rather than ints[x*YWIDTH+y].

EDIT: A simple benchmark suggests that my way is faster without the optimizer, but gcc may optimize better on the simple way for some reason.

http://pastebin.com/YDRuLuXv

If you compile with gcc -O0, the best should be stack, then mine, then normal. If you compile with X_MAX set to large value and Y_MAX set to a small value, and use gcc -O3, mine and stack should be really really fast, but the normal one won't be. If you make X_MAX small and Y_MAX big, the normal way should win (even over the stack method for some reason).

+1  A: 

I think you're micro-optimizing needlessly at too early a stage. Instead of worrying about this, just get the program working correctly the easiest way possible.

If you need a 2D array, just declare it and use it. The reduction in bugs and maintenance will be far more worthwhile than any performance increase, which may not exist at all.

Larry Watanabe
The problem is that it has to be dynamic, and you can't do `new int[XWIDTH][YWIDTH];`, and this would be easier to deal with now and may make a different in cache performance. The main thing is that it's easy and if it works it at least won't hurt anything.
Brendan Long
if you want to allocate a 2D array dynamically, just usea = malloc(sizeof(int *) * ROWS);for (int i = 0; i < ROWS; i++) { a[i] = malloc(sizeof(int) * COLS);}then you can just access elements as a[i][j]
Larry Watanabe
I realize I can do that, but that creates [number of rows] separate chunks of memory (non-continuous). I think I should get better cache performance with one big chunk. I'll do some benchmarks to see if I can prove a difference.
Brendan Long
I did some quick tests. My way generally got a very small but consistent speed improvement. Something like 3% (in a test that does nothing but allocate a huge 2D array and then adds up its elements).
Brendan Long
I added a pastebin of my benchmark. It stacks more favorably towards my way as the `X_MAX` gets bigger. Interestingly, with gcc -O[1-3], my method seems to get optimized better when Y_MAX is small (try `Y_MAX = 1;` then compile with `gcc -O3`), but the easy way does better if X_MAX > Y_MAX.
Brendan Long
and how many minutes will that save in a typical run? or will it be ms?
Larry Watanabe
In frames per second it could make a difference.
Brendan Long
+2  A: 

The problem with that kind of approach is that it is error prone. I would tell yout to wrap the allocation and access to individual elements os your 2D array in a class.

class Array2D
{
private:
    /* Pointer necessary for the choosen implementation */
public:
    Array2D(unsigned int dim1, unsigned int dim2);
    ~Array2D() /* Needed, since you will be allocation memory for this class */
    double operator()(unsigned int x, unsigned int y);
}

In that case, if you ever feel the need of changing the allocation, you can only change the methods implementation, keeping the interface intact. The rest of your code would actually use only the operator() and the constructor. It will help you, also, to prevent memory leaking.

cake
A: 

I found a better way. Boost has a library for multidimensional arrays: boost::multi_array.

Got the idea from this question.

Brendan Long