About the valid uses of if(i = 0)
The problem is that you're taking the problem upside down. The "if" notation is not about comparing two values like in some other languages.
The C/C++ "if" instruction waits for any expression that will evaluate to either a boolean, or a null/non-null value. This expression can include two values comparison, and/or can be much more complex.
For example, you can have:
if(i >> 3)
{
std::cout << "i is less than 8" << std::endl
}
Which proves that, in C/C++, the if expression is not limited to == and =. Anything will do, as long as it can be evaluated as true or false (C++), or zero non-zero (C/C++).
Another C++ valid use:
if(MyObject * pObject = dynamic_cast<MyInterface *>(pInterface))
{
pObject->doSomething() ;
}
And these are simple uses of the if expression (note that this can be used, too, in the for loop declaration line). More complex uses do exist.
After discovering a duplicate of this question at http://stackoverflow.com/questions/3122284/, I decided to complete this answer with an additional bonus, that is, variable injection into a scope, which is possible in C++ because if
will evaluate its expression, including a variable declaration, instead of limiting itself to compare two operands like it is done in other languages:
So, quoting from myself:
Another use would be to use what is called C++ Variable Injection. In Java, there is this cool keyword:
synchronized(p)
{
// Now, the Java code is synchronized using p as a mutex
}
In C++, you can do it, too. I don't have the exact code in mind (nor the exact DDJ's article where I discovered it), but this simple define should be enough for demonstration purposes:
#define synchronized(lock) \
if (auto_lock lock_##__LINE__(lock))
synchronized(p)
{
// Now, the C++ code is synchronized using p as a mutex
}
This is the same way, mixing injection with if and for declaration, you can declare a primitive foreach macro (if you want an industrial-strength foreach, use boost's).
See the following articles for a less naive, more complete and more robust implementation:
How many errors of this kind really happens?
Rarely. In fact, I have yet to remember one, and I am professional since 8 years.
I guess it happened, but then, in 8 years, I did produce a sizeable quantity of bugs. It's just that this kind of bugs did not happen enough to have me remember them in frustration.
In C, you'll have more bugs because of buffer overruns, like :
void doSomething(char * p)
{
strcpy(p, "Hello World, how are you \?\n") ;
}
void doSomethingElse()
{
char buffer[16] ;
doSomething(buffer) ;
}
In fact, Microsoft was burned so hard because of that they added a warning in Visual C++ 2008 deprecating strcpy !!!
How can you avoid most errors?
The very first "protection" against this error is to "turn around" the expression: As you can't assign a value to a constant, this :
if(0 = p) // ERROR : It should have been if(0 == p). WON'T COMPILE !
Won't compile.
But I find this quite a poor solution, because it tries to hide behind style what should be a general programming practice, that is : Any variable that is not supposed to change should be constant.
For example, instead of :
void doSomething(char * p)
{
if(p == NULL) // POSSIBLE TYPO ERROR
return ;
size_t length = strlen(p) ;
if(length == 0) // POSSIBLE TYPO ERROR
printf("\"%s\" length is %i\n", p, length) ;
else
printf("the string is empty\n") ;
}
Trying to "const" as much variables as possible will make you avoid most typo errors, including those not inside "if" expressions :
void doSomething(const char * const p) // CONST ADDED HERE
{
if(p == NULL) // NO TYPO POSSIBLE
return ;
const size_t length = strlen(p) ; // CONST ADDED HERE
if(length == 0) // NO TYPO POSSIBLE
printf("\"%s\" length is %i\n", p, length) ;
else
printf("the string is empty\n") ;
}
Of course, it is not always possible (as some variables do need to change), but I found than most of the variables I use are constants (I keep initializing them once, and then, only reading them).
Conclusion
Usually, I see code using the if(0 == p) notation, but without the const-notation.
To me, it's like having a trash can for recyclables, and another for non-recyclable, and theni n the end, throw them together in the same container.
So, do not parrot a easy style habit hoping it will make your code a lot better. It won't. Use the language constructs as much as possible, which means, in this case, using both the if(0 == p) notation when available, and using of the const keyword as much as possible.