Proxy Design Pattern in C++: Before and after

Before

Direct coupling, lots of start-up and shut-down overhead.

class Image
{
    int m_id;
    static int s_next;
  public:
    Image()
    {
        m_id = s_next++;
        cout << "   $$ ctor: " << m_id << '\n';
    }
    ~Image()
    {
        cout << "   dtor: " << m_id << '\n';
    }
    void draw()
    {
        cout << "   drawing image " << m_id << '\n';
    }
};
int Image::s_next = 1;

int main()
{
  Image images[5];

  for (int i; true;)
  {
    cout << "Exit[0], Image[1-5]: ";
    cin >> i;
    if (i == 0)
      break;
    images[i - 1].draw();
  }
}

Output

   $$ ctor: 1
   $$ ctor: 2
   $$ ctor: 3
   $$ ctor: 4
   $$ ctor: 5
Exit[0], Image[1-5]: 2
   drawing image 2
Exit[0], Image[1-5]: 4
   drawing image 4
Exit[0], Image[1-5]: 2
   drawing image 2
Exit[0], Image[1-5]: 0
   dtor: 5
   dtor: 4
   dtor: 3
   dtor: 2
   dtor: 1


After

Initialization on first use

  1. Design an "extra level of indirection" wrapper class
  2. The wrapper class holds a pointer to the real class
  3. The pointer is initialized to null
  4. When a request comes in, the real object is created "on first use" (aka lazy initialization)
  5. The request is always delegated
class RealImage
{
    int m_id;
  public:
    RealImage(int i)
    {
        m_id = i;
        cout << "   $$ ctor: " << m_id << '\n';
    }
    ~RealImage()
    {
        cout << "   dtor: " << m_id << '\n';
    }
    void draw()
    {
        cout << "   drawing image " << m_id << '\n';
    }
};

// 1. Design an "extra level of indirection" wrapper class
class Image
{
    // 2. The wrapper class holds a pointer to the real class
    RealImage *m_the_real_thing;
    int m_id;
    static int s_next;
  public:
    Image()
    {
        m_id = s_next++;
        // 3. Initialized to null
        m_the_real_thing = 0;
    }
    ~Image()
    {
        delete m_the_real_thing;
    }
    void draw()
    {
        // 4. When a request comes in, the real object is
        //    created "on first use"
        if (!m_the_real_thing)
          m_the_real_thing = new RealImage(m_id);
        // 5. The request is always delegated
        m_the_real_thing->draw();
    }
};
int Image::s_next = 1;

int main()
{
  Image images[5];

  for (int i; true;)
  {
    cout << "Exit[0], Image[1-5]: ";
    cin >> i;
    if (i == 0)
      break;
    images[i - 1].draw();
  }
}

Output

Exit[0], Image[1-5]: 2
   $$ ctor: 2
   drawing image 2
Exit[0], Image[1-5]: 4
   $$ ctor: 4
   drawing image 4
Exit[0], Image[1-5]: 2
   drawing image 2
Exit[0], Image[1-5]: 0
   dtor: 4
   dtor: 2

Code examples