Use the standard `vector` template, and make a `vector` of
`vector`.

The following uses a `std::vector<std::vector<T> >` (note the space between the
two `>` symbols).

#include <vector>
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 { };
// *No need for any of The Big Three!*
// *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 { };
unsigned nrows() const; // *#rows in this matrix*
unsigned ncols() const; // *#columns in this matrix*
private:
std::vector<std::vector<T> > data_;
};
template<typename T>
inline unsigned Matrix<T>::nrows() const
{ return data_.size(); }
template<typename T>
inline unsigned Matrix<T>::ncols() const
{ return data_[0].size(); }
template<typename T>
inline T& Matrix<T>::operator() (unsigned row, unsigned col)
{
if (row >= nrows() || col >= ncols()) throw BoundsViolation();
return data_[row][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][col];
}
template<typename T>
Matrix<T>::Matrix(unsigned nrows, unsigned ncols)
: data_ (nrows)
{
if (nrows == 0 || ncols == 0)
throw BadSize();
for (unsigned i = 0; i < nrows; ++i)
data_[i].resize(ncols);
}

Note how much simpler this is than

the previous:
there is no explicit

`new` in the constructor, and there is no need for
any of

The Big Three (destructor, copy constructor
or assignment operator). Simply put, your code is a

*lot* less likely
to have memory leaks if you use

`std::vector` than if you use explicit

`new T[n]` and

`delete[] p`.

Note also that `std::vector` doesn't force you to allocate numerous
chunks of memory. If you prefer to allocate only one chunk of memory for the
entire matrix, as was done in the previous, just
change the type of `data_` to `std::vector<T>` and add member
variables `nrows_` and `ncols_`. You'll figure out the rest:
initialize `data_` using `data_(nrows * ncols)`, change
`operator()()` to `return data_[row*ncols_ + col];`, etc.