C++ FAQ Celebrating Twenty-One Years of the C++ FAQ!!!
(Click here for a personal note from Marshall Cline.)
Section 16:
16.1 Does delete p delete the pointer p, or the pointed-to-data *p?
16.2 Is it safe to delete the same pointer twice?
16.3 Can I free() pointers allocated with new? Can I delete pointers allocated with malloc()?
16.4 Benefits of new over malloc()?
16.5 Can I use realloc() on pointers allocated via new?
16.6 Checking for NULL after p = new Fred()?
16.7 How can I convince my (older) compiler to automatically check new to see if it returns NULL?
16.8 Checking for NULL before delete p?
16.9 What are the two steps that happen when I say delete p?
16.10 Does p = new Fred() leak memory if the ctor throws an exception?
16.11 How do I allocate / unallocate an array of things?
16.12 What if I forget the [] when deleteing an array allocated via new T[n]?
16.13 Can I drop the [] when deleteing an array of some built-in type (char, int, etc)?
16.14 After p = new Fred[n], how does the compiler know there are n objects to be destructed during delete[] p?
16.15 Is it legal (and moral) for a member function to say delete this?
16.16 How do I allocate multidimensional arrays using new?
16.17 How to simplify the Matrix code from the previous FAQ?
16.18 How to make the Matrix class generic?
16.19 What's another way to build a Matrix template?
16.20 Does C++ have arrays whose length can be specified at run-time?
16.21 Allocating all objects via new, not local/global/static?
16.22 How do I do simple reference counting?
16.23 How do I provide reference counting with copy-on-write semantics?
16.24 How do I provide reference counting with copy-on-write semantics for a hierarchy of classes?
16.25 Preventing people from subverting the reference counting mechanism?
16.26 Can I use a garbage collector in C++?
16.27 What are the two kinds of garbage collectors for C++?
16.28 Where can I get more info on garbage collectors for C++?
[16.18] But the above Matrix class is specific to Fred! Isn't there a way to make it generic?

Yep; just use templates:

Here's how this can be used:

#include "Fred.h"  // To get the definition for class Fred

// The code for Matrix<T> is shown below...
void someFunction(Fred& fred);

void manipulateArray(unsigned nrows, unsigned ncols)
{
  Matrix<Fred> matrix(nrows, ncols);   // Construct a Matrix<Fred> called matrix

  for (unsigned i = 0; i < nrows; ++i) {
    for (unsigned j = 0; j < ncols; ++j) {
      // Here's the way you access the (i,j) element:
      someFunction( matrix(i,j) );

      // You can safely "return" without any special delete code:
      if (today == "Tuesday" && moon.isFull())
        return;     // Quit early on Tuesdays when the moon is full
    }
  }

  // No explicit delete code at the end of the function either
}
Now it's easy to use Matrix<T> for things other than Fred. For example, the following uses a Matrix of std::string (where std::string is the standard string class):
#include <string>

void someFunction(std::string& s);

void manipulateArray(unsigned nrows, unsigned ncols)
{
  Matrix<std::string> matrix(nrows, ncols);   // Construct a Matrix<std::string>

  for (unsigned i = 0; i < nrows; ++i) {
    for (unsigned j = 0; j < ncols; ++j) {
      // Here's the way you access the (i,j) element:
      someFunction( matrix(i,j) );

      // You can safely "return" without any special delete code:
      if (today == "Tuesday" && moon.isFull())
        return;     // Quit early on Tuesdays when the moon is full
    }
  }

  // No explicit delete code at the end of the function either
}
You can thus get an entire family of classes from a template. For example, Matrix<Fred>, Matrix<std::string>, Matrix< Matrix<std::string> >, etc.

Here's one way that the template can be implemented:

template<typename T>  // See section on templates for more
class Matrix {
public:
  Matrix(unsigned nrows, unsigned ncols);
  // Throws a BadSize object if either size is zero
  class BadSize { };

  // Based on the Law Of The Big Three:
 ~Matrix();
  Matrix(const Matrix<T>& m);
  Matrix<T>& operator= (const Matrix<T>& m);

  // Access methods to get the (i,j) element:
  T&       operator() (unsigned i, unsigned j);         subscript operators often come in pairs
  T const& operator() (unsigned i, unsigned j) const;   subscript operators often come in pairs
  // These throw a BoundsViolation object if i or j is too big
  class BoundsViolation { };

private:
  unsigned nrows_, ncols_;
  T* data_;
};

template<typename T>
inline T& Matrix<T>::operator() (unsigned row, unsigned col)
{
  if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
  return data_[row*ncols_ + col];
}

template<typename T>
inline T const& Matrix<T>::operator() (unsigned row, unsigned col) const
{
  if (row >= nrows_ || col >= ncols_)
    throw BoundsViolation();
  return data_[row*ncols_ + col];
}

template<typename T>
inline Matrix<T>::Matrix(unsigned nrows, unsigned ncols)
  : nrows_ (nrows)
  , ncols_ (ncols)
//, data_  <--initialized below (after the 'if/throw' statement)
{
  if (nrows == 0 || ncols == 0)
    throw BadSize();
  data_ = new T[nrows * ncols];
}

template<typename T>
inline Matrix<T>::~Matrix()
{
  delete[] data_;
}