A few people use

`[][]`

`[][]`

The point of the previous two FAQs is that

`m(i,j)`

Now everybody knows that

*you*are different. You are clairvoiant with perfect knowledge of the future, and you

*know*that no one will ever find any benefit from changing your matrix's internal data structure. Plus you are a

*good*programmer, unlike those slobs out there that occasionally pass wrong parameters, so you don't need to worry about pesky little things like parameter checking. But even though you don't need to worry about maintenance costs (no one ever needs to change your code), there might be one or two other programmers who aren't quite perfect yet. For them, maintenance costs are high, defects are real, and requirements change. Believe it or not, every once in a while they need to (better sit down) change their code.

Okay, my thongue wath in my theek. But there was a point. The point was that encapsulation and parameter-checking are not crutches for the weak. It's smart to use techniques that make encapsulation and/or parameter checking easy. The

`m(i,j)`

Having said all that, if you find yourself maintaining a billion-line app where the original team used

`m[i][j]`

*want*to use

`m[i][j]`

If you merely want to check parameters, just make sure the outer

`operator[]`

`operator[]`

*theoretical*cost is still O(rows*cols), but in practice, the overhead of the memory allocator (

`new`or

`malloc`) can be

*much*larger than anything else, and that overhead can swamp the other costs. For instance, on two of the world's best known C++ compilers, the separate-allocation-per-row technique was 10x slower than the than one-allocation-for-the-entire-matrix technique. 10% is one thing, 10x is another.

If you want to check the parameters without the above overhead and/or if you want to encapsulate (and possibly change) the matrix's internal data structure, follow these steps:

- Add
to the`operator()(unsigned row, unsigned col)``Matrix`class. - Create nested class
. It should have a ctor with parameters`Matrix::Row` , and it should store those two values in its`(Matrix& matrix, unsigned row)``this`object. - Change
so it returns an object of class`Matrix::operator[](unsigned row)` , e.g.,`Matrix::Row` .`{ return Row(*this,row); }` - Class
then defines its own`Matrix::Row` which turns around and calls, you guessed it,`operator[](unsigned col)` . If the`Matrix::operator()(unsigned row, unsigned col)` data members are called`Matrix::Row` and`Matrix& matrix_` , the code for`unsigned row_` will be`Matrix::Row::operator[](unsigned col)``{ return matrix_(row_, col); }`

`const`overloading by repeating the above steps. You will create the

`const`version of the various methods, and you will create a new nested class, probably called

`Matrix::ConstRow`

`Matrix const&`

`Matrix&`

Final step: find the joker who failed to read the previous FAQ and thonk him in the noggin.

If you have a decent compiler and if you judiciously use inlining, the compiler should optimize away the temporary objects. In other words, the

`operator[]`

`Matrix::operator()(unsigned row, unsigned col)`

`Matrix::operator()(unsigned row, unsigned col)`

`Matrix::operator()(unsigned row, unsigned col)`

## No comments:

## Post a Comment