From: schreib@messua.informatik.rwth-aachen.de (Dirk Schreib)
Subject: Different reader/writer functions for arrays???
Organization: Rechnerbetrieb Informatik  /  RWTH Aachen
Date: 15 Sep 92 14:42:21 GMT


Question:

   I'd like to create a generic, dynamic array, which has different
   operations for reading and writing.

   The purpose is to handle accesses to elements that are out of the
   array's bounds. In case of a write access, the array should resize
   itself, in case of a read access, it should return a default
   object.


First thought: trivial!

  Make a template class (name: "Grid"), overload operator() 
  (I want a multidimensional array)
  and return a description object. (name: "D")

  For this description class, overload operator =() for assignment and
  operator T () for reading. (array has type T)


This works... but:


  Maybe T is a "pointer to class".

  You cannot write grid(x,y)->f() because grid(x,y) is of type D.


Second thought: A little bit complex!

  I've overloaded operator ->() for class D. Also
  operator &().

This works...but:

  You have to overload nearly all operators which will be needed.


But there are still problems:

  There might be functions like:

  void foo(T & arrayobject);

  Is this a write or read access?

  or

  operator >> (ifpstream &, T &);

  This is a write access!! But how to handle?

  or

  delete grid(x,y) will not work, but delete (T *) grid(x,y) will.


Last thought: Too complex!!


Have I missed the point? Is there any feature in C++ which
permits this?

Any help would be appreciated.


Dirk


P.S.: I've included my template-version.

---------------------------------------------------
#include <iostream.h>
#include <assert.h>

template <class T>
class Grid
    {
protected:
    int xs,ys;
    int dx, dy;
    T * mem;
    T Empty;
public:
    void grow(int nxs, int nys);
    int XSize() const { return xs;};
    int YSize() const { return ys;};

    class D;

    friend D;

    class D
        {
        Grid & g;
        int x,y;
    public:
        D(Grid & ng, int nx, int ny): g(ng), x(nx), y(ny) {};

        T operator ->()
            {
            if ( (x >= g.xs ) || ( y >= g.ys))
                {
                return g.Empty;
                }
            else
                return g.mem[x*g.ys+y];
            };

        T * operator & ()
            {
            if ( (x >= g.xs ) || ( y >= g.ys))
                return &g.Empty;
            else
                return &g.mem[x*g.ys+y];
            };

        operator T ()
            {
            if ( (x >= g.xs ) || ( y >= g.ys))
                return g.Empty;
            else
                return g.mem[x*g.ys+y];
            };

        T operator = (const T& t)
            {
            if ( (x >= g.xs ) || ( y >= g.ys))
                g.grow(x+1,y+1);
            return g.mem[x*g.ys+y] = t;
            };
        };


    Grid(T aEmpty,int nxs = 1, int nys = 1, int ndx = 0, int ndy = 0):
      xs(nxs), ys(nys), dx(ndx), dy(ndy), Empty(aEmpty)
        {
        mem = new T[xs*ys];
        memset(mem, 0, xs * ys * sizeof(T));
        };

    ~Grid()
        {
        delete [] mem;
        };

    D operator() (int x, int y)
        {
        assert( (x>=0) && (y>=0) );
        return D(*this, x,y);
        };
    };

template <class T>
void Grid<T>::grow(int nxs, int nys)
    {
    if (nxs < xs) nxs = xs;
    if (nys < ys) nys = ys;
    nxs += dx; nys +=dy;
    T * help = new T[nxs*nys];
    memset(help, 0, nxs * nys * sizeof(T));
    for (int x=0; x <xs; x++)
        for(int y=0; y <ys; y++)
            help[x*nys+y] = mem[x*ys+y];
    xs = nxs; ys = nys;
    delete [] mem;
    mem = help;
    };


#endif

-- 
Dirk Schreib, Markt 54, 5100 Aachen,  Germany
Tel.: +49 241 30896,       FAX: +49 241 24359
CompuServe: 100021,2576
Email: schreib@POOL.Informatik.RWTH-Aachen.DE