Bound-Checked Array Using Smart Pointer
#ifndef _SAFEARR_H_ #define _SAFEARR_H_ #include <iostream> #include <string> #include <algorithm> #include <memory> using namespace std; template <typename T> class SafeArr { public: // Create a new array of the given size. SafeArr(int asize) { m_size = asize; m_space.reset(new T[asize]); } // Create an array as a copy of another. SafeArr(const SafeArr &other) { copyin(other); } // Find out how large this is. int size() const { return m_size; } // Perform an array assignment. Delete our space, then make us a // copy of other. SafeArr & operator=(const SafeArr &other) { copyin(other); return *this; } // Store into the array, or print an error message and don't // change the aray. void store(int pos, const T &tostore) { if(pos < m_size && pos >= 0) { m_space[pos] = tostore; } else { cerr << pos << " out of bounds on store" << endl; } } // Fetch from pos, or, if pos is out of bounds, print a message // and return T(). T fetch(int pos) const { if(pos < m_size && pos >= 0) { return m_space[pos]; } else { cerr << pos << " out of bounds on fetch" << endl; return T(); } } // Alternate version of fetch that works when there is no T() // (No default constructor for T.) Fills in the result through // the parameter void fetch(int pos, T &fetched) const { if(pos < m_size && pos >= 0) { fetched = m_space[pos]; } else { cerr << pos << " out of bounds on fetch" << endl; } } // Array printer. Works if T can be printed with <<. void print(ostream &out, string sep = " ") const { for(int n = 0; n < m_size; ++n) { out << m_space[n]; if(n < m_size-1) out << " "; } } private: unique_ptr<T[]> m_space; int m_size; // Size of the array. // Make us a copy of the other array. Allocates m_space of // the same size, then copies the contents of other.m_size into it, // and copies m_size. void copyin(const SafeArr &other) { m_space.reset(new T[other.m_size]); m_size = other.m_size; copy(other.m_space.get(), other.m_space.get() + other.m_size, m_space.get()); } }; /* * This allows the array to be printed with <<, assuming T can be. */ template <typename T> ostream & operator<<(ostream & strm, const SafeArr<T> &arr) { arr.print(strm); return strm; } #endif

This version of the safe array class uses unique_ptr to hold the pointer to the array space. It will run with the same driver; simply change the name on the #include line. Differences:

  1. The declaration of m_space at the bottom of the class.
  2. The array allocation in the constructor is now wrapped in a reset call which which passes allocation responsibility to the smart pointer.
  3. The private copyin method also allocates using a reset, which frees the previous allocation, if any. This means that the assignment operator no longer needs to delete.
  4. The private copyin method also uses the get operation on unique_ptr, which simply returns the plain pointer that it holds. This is a bit of a hack, but I couldn't find a better way to call copy from the algorithm library.
  5. There is no destructor. When the object is destroyed, the unique pointer is destroyed also, and it deletes the array.