[comp.lang.c++] Multidimensional Arrays accessed with [] operator

heintze.peewee.enet.dec.com (Sieg Heintze) (07/04/90)

During Spring Semester, I was simulating the write path of a magnetic-optical 
storage (MO) disk.   I needed a five dimenensional array of floats whose 
dimensions would be determined at run time.  I was  also determined to access
the elements with the [] operator regardless of whether I was in a function or 
not!

I wanted to create  a special array class and overload the [] operator.

As you may know, there is a serious problem with C and the default array
syntax for C++. I refer you to page 120 of Stroustrup's "the C++ Programming
Language" where he says you cannot pass arrays, you can only pass pointers and
inside the recieving subprogram you have to compute your own offsets. Even
Bjarne (in the comments) says that this is obscure!

Someone kindly gave an example of using the [] operator to access a pseudo 
array.  This what was done was to use [] to access an array of pointers. So 
for each successive dimension, you have another array of pointers.  Each array 
of pointers is contained an a class that also holds the bounds for that row or 
column.

Well this was very nice and even pratical for two dimensional arrays.  But I 
was afraid to try it with a five dimensional pseudo array!  The redundant 
overhead would be staggering!

How can I efficiently overload [] for a five dimensional pseudo array.

Better yet, how can I efficiently overload [] for a five dimensional real 
array (ie, an contiguous array that does not use pointers to find a element 
given the row and column).

Incidently, for my simulation, I gave up on overloading [] and just used the 
features of C to access entity declared as  "float**** modisk;".   This did 
not, of course, have the bounds checking I wanted.

heintze@genral.enet.dec.com
Digital Equipment Corporation
1110 Chapel Hills Drive  CXN2-2/35
Colorado Springs, CO 80920-3995
719-260-2184

sdm@cs.brown.edu (Scott Meyers) (07/04/90)

In article <13060@shlump.nac.dec.com> heintze.peewee.enet.dec.com (Sieg Heintze) writes:
>storage (MO) disk.   I needed a five dimenensional array of floats whose 
>dimensions would be determined at run time.  I was  also determined to access
>the elements with the [] operator regardless of whether I was in a function or 
>not!

>How can I efficiently overload [] for a five dimensional pseudo array.

Here's a possibility:  create a class ArrayIndex that holds all the indices
of the array, then define operator[] in your array class to take a single
argument of type ArrayIndex.  You can then do bounds checking, etc., on the
ArrayIndex object, plus you can use "natural" syntax for multidimensional
array.  In general, you write 

    arrayObject[a,b,c,d,e]

which constructs an object of type ArrayIndex from the a, then uses the
comma operator of ArrayIndex to eat up the b, c, d, and e arguments and
finish the "construction" of the ArrayIndex object.

    const MAX_DIMENSIONS = 10;      // no array has more than 10 indices

    class ArrayIndex {
    private:
      int nextIndex;
      int indices[MAX_DIMENSIONS];

    public:
      ArrayIndex(int i): nextIndex(0)
        { indices[nextIndex++] = i; }

      ArrayIndex& operator,(int i)
        {
          if (nextIndex < MAX_DIMENSIONS)
            indices[nextIndex++] = i;
          // else signal an error (too many indices)

          return *this;
        }

      int numIndices() { return nextIndex; }

      const int& operator[](int i) { return indices[i]; }
    };


    class Int5DArray {
    private:
      int lowBounds[5];
      int highBounds[5];
      int *data;

    public:
      Int5DArray (int l0, int h0,
                  int l1, int h1,
                  int l2, int h2,
                  int l3, int h3,
                  int l4, int h4)
        {
          // check bounds for validity (i.e., hi >= li for 0<=i<=4), store
          // them in the appropriate places in lowBounds and highBounds, and
          // allocate memory for data
        }

      int& operator[](ArrayIndex i)
        {
          // if (i.numIindices != 5)
          //   signal an error (wrong number of indices)
          // if ((i[0] < lowBounds[0]) || (i[0] > highBounds[0]) ...)
          //   signal an error (index out of bounds)

          // return the appropriate data
        }

    };

With this approach you lose compile-time checking that the number of array
indices in a use matches the number the array actually has, but the test is
performed at runtime instead.  You gain generality, and this approach can
be nicely combined with parameterized types to give you generic
multidiminsional arrays.  Note that some people may object to overloading
the comma operator, since it can really obscure things, but since the
syntax you use here isn't legal with "normal" arrays, confusion shouldn't
be too bad.

Now to be totally truthful, I didn't check this code to make sure it works,
but it does at least get through cfront without any errors.  Presuming that
it works (or can be made to work), it will certainly be more efficient than
four levels of pseudo-arrays, but it still may not be efficient enough.  I
suspect you could write a class-specific operator new/delete to increase
the speed of construction/destruction of ArrayIndex objects, since each is
used only once.  

Scott 
sdm@cs.brown.edu