One of the typical usage of the references is returning from function by reference rather than by value. Returning reference often more effective than copying. In some cases, however, copying is a must.
template <typename T> class matrix { public: // ... T& operator()(int i, int j) { return v[i*cols+j]; } const T& operator()(int i, int j) const { return v[i*cols+j]; } matrix& operator+=( const matrix& other) { for (int i = 0; i < cols*rows; ++i) v[i] += other.v[i]; } private: // ... T* v; }; template <typename T> matrix<T> operator+( const matrix<T>& left, const matrix<T>& right) { matrix<T> result(left); result += right; return result; }
Let us discover the return values one-by-one:
T& operator()(int i, int j) { return v[i*cols+j]; }
This function returns reference to the selected value, allowing clients to modify the appropriate element of the matrix:
matrix<double> dm(10,20); // ... dm(2,3) = 3.14; // modify metrix element cout << dm(2,3); // copies matrix element dm(2,3) += 1.1; // modify matrix element double& dr = dm(2,3); // doesn't copies dr += 1.1; // modify matrix element
A second version of operator() is presented to read constant matrices.
const T& operator()(int i, int j) const { return v[i*cols+j]; }
This const memberfunction must return const reference, otherwise the const-correctness would be leaking:
const matrix<double> cm = dm; // ... cm(2,3) = 3.14; // syntax error: returns with const reference cout << cm(2,3); // ok: copies (read) matrix element cm(2,3) += 1.1; // syntax error: returns with const reference double& dr = cm(2,3); // syntax error: const reference // does not convert to reference const double& cdr = cm(2,3); // ok, doesn't copy
Most assignment operators defined with (non-const) reference type as return value:
matrix& operator=(const matrix& other); matrix& operator+=( const matrix& other) { for (int i = 0; i < cols*rows; ++i) v[i] += other.v[i]; }
This is more effective than a value returning type, and also avoiding unneccessary restrictions:
dm1 = dm2 = dm3; ++( dm1 += dm2 );
In the previous examples returning reference (or constant reference) was safe, because the memory area which was referred survived the operation. In the next addiotion returning a reference (or constant reference) would be a major fault:
template <typename T> matrix<T> operator+( const matrix<T>& left, const matrix<T>& right) { matrix<T> result(left); // local variable: automatic storage result += rigth; return result; // result will disappear: must copy }