First, the best thing to do is get rid of the macro if at all possible. In fact, get rid of all macros: they're evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4, regardless of whether the contain an if (but they're especially evil if they contain an if).
But if you can't (or don't want to) kill the macro that contains an if, here's how to make it less evil:
Suppose the macro looks like this:
This will cause big problems if someone uses that macro in an if statement:
The problem is that the else baz nests with the wrong if: the compiler sees this:
Obviously that's a bug.
The easy solution is to require {...} everywhere, but there's another solution that I prefer even if there's a coding standard that requires {...} everywhere (just in case someone somewhere forgets): add a balancing else to the macro definition:
Now the compiler will see a balanced set of ifs and elses:
Like I said, I personally do the above even when the coding standard calls for {...} in all the ifs. Call me paranoid, but I sleep better at night and my code has fewer bugs.
Note: you need to make sure to put a ; at the end of the macro usage (not at the end of the macro definition!!). For example, the macro usage should look like this:
Note: there is another #define macro (do {...} while (false)) that is fairly popular, but that has some strange side-effects when used in C++.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Answer: Choke, gag, cough. Macros are evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4. Kill them all!!
But if you can't (or don't want to) kill them, here's how to make them less evil:
Suppose the macro looks like this:
This can cause problems if someone uses the macro in a context that demands a single statement. E.g.,
The naive solution is to wrap the statements inside {...}, such as this:
But this will cause compile-time errors with things like the following:
since the compiler will see a } ; else which is illegal:
The usual solution in C was to wrap the statements inside a do { <statements go here> } while (false), since that will execute the <statements go here> part exactly once. E.g., the macro might look like this:
Note that there is no ; at the end of the macro definition. The ; gets added by the user of the macro, such as the following:
This will expand to the following (note that the ; added by the user goes after (and completes) the "} while (false)" part):
The only problem with this is that it looks like a loop, and some C++ compilers refuse to "inline expand" any method that has a loop in it.
So in C++ the best solution is to wrap the statements in an if (true) { <statements go here> } else construct (note that the else is dangling, just like the situation described in the previous FAQ):
Now the code will expand into this (note the balanced set of ifs and elses):
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Groan. I really hate macros. Yes they're useful sometimes, and yes I use them. But I always wash my hands afterwards. Twice. Macros are evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4.
Okay, here we go again, desperately trying to make an inherently evil thing a little less evil.
First, the basic approach is use the ISO/ANSI C and ISO/ANSI C++ "token pasting" feature: ##. On the surface this would look like the following:
Suppose you have a macro called "MYMACRO", and suppose you're passing a token as the parameter of that macro, and suppose you want to concatenate that token with the token "Tmp" to create a variable name. For example, the use of MYMACRO(Foo) would create a variable named "FooTmp" and the use of MYMACRO(Bar) would create a variable named "BarTmp". In this case the naive approach would be to say this:
However you need a double layer of indirection when you use ##. Basically you need to create a special macro for "token pasting" such as:
Trust me on this you really need to do this! (And please nobody write me saying it sometimes works without the second layer of indirection. Try concatenating a symbol with __LINE__ and see what happens then.)
Then replace your use of a ## Tmp with name2(a,Tmp):
And if you have a three-way concatenation to do (e.g., to paste three tokens together), you'd create a name3() macro like this:
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Because "\t" is a tab character.
You should use forward slashes ("/") rather than backslashes ("\") in your #include filenames, even on an operating system that uses backslashes such as DOS, Windows, OS/2, etc. For example:
Note that you should use forward slashes ("/") on all your filenames, not just on your #include files.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Yep.
The following code used to be legal, but not any more, since i's scope is now inside the for loop only:
If you're working with some old code that uses a for loop variable after the for loop, the compiler will (hopefully!) give you wa warning or an error message such as "Variable i is not in scope".
Unfortunately there are cases when old code will compile cleanly, but will do something different the wrong thing. For example, if the old code has a global variable i, the above code if (i != 10) silently change in meaning from the for loop variable i under the old rule to the global variable i under the current rule. This is not good. If you're concerned, you should check with your compiler to see if it has some option that forces it to use the old rules with your old code.
Note: You should avoid having the same variable name in nested scopes, such as a global i and a local i. In fact, you should avoid globals althogether whenever you can. If you abided by these coding standards in your old code, you won't be hurt by a lot of things, including the scoping rules for for loop variables.
Note: If your new code might get compiled with an old compiler, you might want to put {...} around the for loop to force even old compilers to scope the loop variable to the loop. And please try to avoid the temptation to use macros for this. Remember: macros are evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
If you declare both char f() and float f(), the compiler gives you an error message, since calling simply f() would be ambiguous.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
A persistent object can live after the program which created it has stopped. Persistent objects can even outlive different versions of the creating program, can outlive the disk system, the operating system, or even the hardware on which the OS was running when they were created.
The challenge with persistent objects is to effectively store their member function code out on secondary storage along with their data bits (and the data bits and member function code of all member objects, and of all their member objects and base classes, etc). This is non-trivial when you have to do it yourself. In C++, you have to do it yourself. C++/OO databases can help hide the mechanism for all this.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
(On one C++ implementation, this prints 0.429993)
Disclaimer: Frustration with rounding/truncation/approximation isn't really a C++ issue; it's a computer science issue. However, people keep asking about it on comp.lang.c++, so what follows is a nominal answer.
Answer: Floating point is an approximation. The IEEE standard for 32 bit float supports 1 bit of sign, 8 bits of exponent, and 23 bits of mantissa. Since a normalized binary-point mantissa always has the form 1.xxxxx... the leading 1 is dropped and you get effectively 24 bits of mantissa. The number 1000.43 (and many, many others) is not exactly representable in float or double format. 1000.43 is actually represented as the following bitpattern (the "s" shows the position of the sign bit, the "e"s show the positions of the exponent bits, and the "m"s show the positions of the mantissa bits):
The shifted mantissa is 1111101000.01101110000101 or 1000 + 7045/16384. The fractional part is 0.429992675781. With 24 bits of mantissa you only get about 1 part in 16M of precision for float. The double type provides more precision (53 bits of mantissa).
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Use a forward declaration.
Sometimes you must create two classes that use each other. This is called a circular dependency. For example:
The Fred class has a member function that returns a Barney*, and the Barney class has a member function that returns a Fred. You may inform the compiler about the existence of a class or structure by using a "forward declaration":
This line must appear before the declaration of class Fred. It simply informs the compiler that the name Barney is a class, and further it is a promise to the compiler that you will eventually supply a complete definition of that class.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
The order of class declarations is critical.
The compiler will give you a compile-time error if the first class contains an object (as opposed to a pointer to an object) of the second class. For example,
One way to solve this problem is to reverse order of the classes so the "used" class is defined before the class that uses it:
Note that it is never legal for each class to fully contain an object of the other class since that would imply infinitely large objects. In other words, if an instance of Fred contains a Barney (as opposed to a Barney*), and a Barney contains a Fred (as opposed to a Fred*), the compiler will give you an error.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
The order of class declarations is critical.
The compiler will give you a compile-time error if the first class contains an inline function that invokes a member function of the second class. For example,
One way to solve this problem is to move the offending member function into the Barney.cpp file as a non-inline member function. Another way to solve this problem is to reverse order of the classes so the "used" class is defined before the class that uses it:
Just remember this: Whenever you use forward declaration, you can use only that symbol; you may not do anything that requires knowledge of the forward-declared class. Specifically you may not access any members of the second class.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Because the std::vector<> template needs to know the sizeof() its contained elements, plus the std::vector<> probably accesses members of the contained elements (such as the copy constructor, the destructor, etc.). For example,
One solution to this problem is to change Barney so it uses a std::vector<> of Fred pointers rather than a std::vector<> of Fred objects:
Another solution to this problem is to reverse the order of the classes so Fred is defined before Barney:
Just remember this: Whenever you use a class as a template parameter, the declaration of that class must be complete and not simply forward declared.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Because floating point arithmetic is different from real number arithmetic.
Here's a simple example:
The above "surprise" message will appear on some (but not all) compilers/machines. But even if your particular compiler/machine doesn't cause the above "surprise" message (and if you write me telling me whether it does, you'll show you've missed the whole point of this FAQ), floating point will surprise you at some point. So read this FAQ and you'll know what to do.
The reason floating point will surprise you is that float and double values are normally represented using a finite precision binary format. In other words, floating point numbers are not real numbers. For example, in your machine's floating point format it might be impossible to exactly represent the number 0.1. By way of analogy, it's impossible to exactly represent the number one third in decimal format (unless you use an infinite number of digits).
To dig a little deeper, let's examine what the decimal number 0.625 means. This number has a 6 in the "tenths" place, a 2 in the "hundreths" place, and a 5 in the "thousanths" place. In other words, we have a digit for each power of 10. But in binary, we might, depending on the details of your machine's floating point format, have a bit for each power of 2. So the fractional part might have a "halves" place, a "quarters" place, an "eighths" place, "sixteenths" place, etc., and each of these places has a bit.
Let's pretend your machine represents the fractional part of floating point numbers using the above scheme (it's normally more complicated than that, but if you already know exactly how floating point numbers are stored, chances are you don't need this FAQ to begin with, so look at this as a good starting point). On that pretend machine, the bits of the fractional part of 0.625 would be 101: 1 in the "halves" place, 0 in the "quarters" place, and 1 in the "eighths" place. In other words, 0.625 is 1/2 + 1/8.
But on this pretend machine, 0.1 cannot be represented exactly since it cannot be formed as a sum of (negative) powers of 2 at least not without an infinite number of (negative) powers of 2. We can get close, but we can't represent it exactly. In particular we'd have a 0 in the "halves" place, a 0 in the "quarters" place, a 0 in the "eighths" place, and finally a 1 in the "sixteenths" place, leaving a remainder of 1/10 - 1/16 = 3/80. Figuring out the other bits is left as an exercise (hint: look for a repeating bit-pattern).
The message is that some floating point numbers cannot always be represented exactly, so comparisons don't always do what you'd like them to do. In other words, if the computer actually multiplies 10.0 by 1.0/10.0, it might not exactly get 1.0 back.
That's the problem. Now here's the solution: be very careful when comparing floating point numbers for equality. For example:
Here's a (probably) smarter way to compare two floating point numbers (note that std::numeric_limits<double>::epsilon() is a very small double-precision number):
Of course you can write some utility routines to encapsulate these funny pieces of code, such as:
Then your code can be a little easier to read:
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Aug 15, 2001