CS253: Software Development with C++

Spring 2021

Proxy Objects

Show Lecture.ProxyObjects as a slide show.

CS253 Proxy Objects

The problem

// C style
int foo[2][3];
foo[1][2] = 24;
cout << foo[1][2];
// Using object
TwoD bar(2,3);
bar[1][2] = 24;
cout << bar[1][2];

Start Small

Let’s start with a one-dimensional array object:

class OneD {
    const int size;
    int *const data;
  public:
    OneD(int size) : size(size), data(new int[size]) { }
    int &operator[](int i) { return data[i]; }
};
OneD a(42);
a[10] = 33;
a[20] = 55;
cout << a[10]+a[20];
88

First naïve 2D attempt

That worked ok, so let’s add a second argument to operator[]:

class TwoD {
    const int height;
    int *const data;
  public:
    TwoD(int w, int h) : height(h), data(new int[w*h]) { }
    int &operator[](int x, int y) { return data[x*height + y]; }
};
c.cc:6: error: 'int& main()::TwoD::operator[](int, int)' must have exactly one 
   argument

Oops—operator[] takes only one argument.

Regroup

Second attempt

class TwoD {
    const int height;
    int *const data;
  public:
    TwoD(int w, int h) : height(h), data(new int[w*h]) { }
    int &operator()(int x, int y) { return data[x*height + y]; }
};
TwoD a(2,3);
a(1,2) = 24;
cout << a(1,2);
24

Analyze

New approach:

Use a proxy class

struct Proxy {
    int *const dp;
    Proxy(int *dataptr) : dp(dataptr) { }
    int &operator[](int y) { return dp[y]; }
};
class TwoD {
    const int height;
    int *const data;
  public:
    TwoD(int w, int h) : height(h), data(new int[w*h]) { }
    Proxy operator[](int x) { return &data[x*height]; }
};
TwoD a(2,3);
a[1][2] = 24;
cout << a[1][2];
24

Adjustment

With a nested class

class TwoD {
    struct Proxy {
        int *const dp;
        Proxy(int *dataptr) : dp(dataptr) { }
        int &operator[](int y) { return dp[y]; }
    };
    const int height;
    int *const data;
  public:
    TwoD(int w, int h) : height(h), data(new int[w*h]) { }
    Proxy operator[](int x) { return &data[x*height]; }
};
TwoD a(2,3);
a[1][2] = 24;
cout << a[1][2];
24

Better memory management

class TwoD {
    struct Proxy {
        int *const dp;
        Proxy(int *dataptr) : dp(dataptr) { }
        int &operator[](int y) { return dp[y]; }
    };
    const int height;
    unique_ptr<int[]> data;
  public:
    TwoD(int w, int h) : height(h), data(new int[w*h]) { }
    Proxy operator[](int x) { return &data[x*height]; }
};
TwoD a(2,3);
a[1][2] = 24;
cout << a[1][2];
24

Felt guilty about not freeing the memory, so used a unique_ptr<int[]> instead of int *.