Go back to Richel Bilderbeek's homepage.
Go back to Richel Bilderbeek's C++ page.
This is the answer of Exercise #2: correct function declarations.
const int GetRows(const Database d); //Incorrect! |
This function probably only read from a Database (due to the const argument). But instead of reading from the original database, a (probably expensive) copy of the database is passed into the function. This makes the answer:
const int GetRows(const Database& d); |
void main(); //Incorrect! |
main has return type int [1-5].
int main(); |
//Incorrect! |
Humans tend to think 'x-y-ordered' instead of 'y-x-ordered', probably because x is before y in the alphabet. It is therefore 'funny' to let a function's arguments be y-x-ordered. Even if the two-dimensional std::vector is y-x-ordered, it is more natural/human to first pass an x, then a y.
void Set(std::vector<std::vector<double> >& v, const int x, const int y, const double value); |
const int Sum(std::vector<int> v); //Incorrect! |
Even worse then item #0: calculating the sum of a std::vector implies only reading from it (thus, a const argument is required) without wanting to make a possibly expensive copy (thus, the std::vector must be given by reference).
const int Sum(const std::vector<int>& v); |
const int Swap(int& a, int& b); //Incorrect |
What would the returned int be? An error code? The difference between a and b? Or the sum of a and b? How brilliant and important this returned int is, it confuses people. Make Swap return nothing. After calling Swap, you can still return error codes, calculate the difference and sum of a and b.
void Swap(int& a, int& b); |
//Incorrect |
First, how can std::cout on the word 'hello' ever fail? It appears this function will always return a no-error code (often zero).
Except for that, why return an error code, when you can also throw an error type (that is, an exception)? The purpose of exceptions are to replace error codes, because these are less ambiguent then error code (for example, zero is not always the no-error code).
Finally, if std::cout fails, it will throw an exception in the first place! The purpose of SayHello is (next to, std::cout the word hello) not to catch this exception and convert it to an error code.
Let SayHello say hello and let the caller of SayHello catch the (improbable) exceptions.
void SayHello(); |
//Set a value in an x-y-ordered 2D-vector |
First (similar to #2), why name the arguments i and j, when writing x and y is more natural/human? Sure, programmers might like to use i and j in their for-loops, but a coordinat in a std::vector suggests using x and y as parameter names.
Secondly (although I personally feel it is more correct), one should not pass an int or double by reference. Build-in data types should be passed by value.
//Set a value in an x-y-ordered 2D-vector |
const double MeanAndStdDev(const std::vector<double>& v, double& mean); //Incorrect! |
A way to be able to let a function return two values. But it might feel unnatural: passing the mean by reference and returning the standard deviation. In my humble opinion, if you use references to 'return' multiple values, uses references for all values.
void MeanAndStdDev(const std::vector<double>& v, double& mean, double& stdDev); |
An alternative that I would personally also approve (but do not prefer) is to return a std::pair. In this std::pair, it is suggested that the first element is the mean, where the second element is the standard deviation.
const std::pair<double,double> MeanAndStdDev(const std::vector<double>& v); |
void CoutWidget(const Widget& w); |
If one writes the above function, one has to write the following:
Widget w; |
But actually, one probably would have wanted to be able to write the following:
Widget w; |
Also, if you want to stream Widget to a std::ostream, why not stream it to any std::ostream?
std::ostream& operator<<(std::ostream& os, const Widget& w); |
//Member function in the interface |
Make interface easy to use correctly and hard to use incorrectly (Meyers). Setting a certain color on a certain square/position of a Rubik's cube is the equivalent of painting a certain color of a certain square (people who actually cheat this way, swap the stickers on the cube). This makes the function very error prone.
When you use a real Rubik's cube, you can only turn multiple squares. This suggests that you might also want to write functions that turns multiple squares (at a certain position) in a certain direction.
//Member function in the interface |
Go back to Richel Bilderbeek's C++ page.
Go back to Richel Bilderbeek's homepage.