[16.17] But the previous FAQ's code is SOOOO tricky and error prone! Isn't there a simpler way?

Yep.

The reason the code in the previous FAQ was so
tricky and error prone was that it used pointers, and we know that
pointers and arrays are evil. The solution is to
encapsulate your pointers in a class that has a safe and simple interface. For
example, we can define a `Matrix` class that handles a rectangular
matrix so our user code will be vastly simplified when compared to the
the rectangular matrix code from the previous FAQ:

// *The code for *`class Matrix` is shown below...
void someFunction(Fred& fred);
void manipulateArray(unsigned nrows, unsigned ncols)
{
Matrix matrix(nrows, ncols); // *Construct a *`Matrix` 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
}

The main thing to notice is the lack of clean-up code. For example, there
aren't any

`delete` statements in the above code, yet there will be

*no*
memory leaks, assuming only that the

`Matrix` destructor does its job
correctly.

Here's the `Matrix` code that makes the above possible:

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(Matrix const& m);
Matrix& operator= (Matrix const& m);
// *Access methods to get the *`(i,j)` element:
Fred& operator() (unsigned i, unsigned j); *← subscript operators often come in pairs*
Fred 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_;
Fred* data_;
};
inline Fred& Matrix::operator() (unsigned row, unsigned col)
{
if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
return data_[row*ncols_ + col];
}
inline Fred const& Matrix::operator() (unsigned row, unsigned col) const
{
if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
return data_[row*ncols_ + col];
}
Matrix::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 Fred[nrows * ncols];
}
Matrix::~Matrix()
{
delete[] data_;
}

Note that the above

`Matrix` class accomplishes two things: it moves
some tricky memory management code from the user code (e.g.,

`main()`)
to the class, and it reduces the overall bulk of program. The latter point is
important. For example, assuming

`Matrix` is even mildly reusable,
moving complexity from the users [plural] of

`Matrix` into

`Matrix` itself [singular] is equivalent to moving complexity from the
many to the few. Anyone who has seen

*Star Trek 2* knows that the good of
the many outweighs the good of the few... or the one.