FAQs in section [34]:
[34.1] What should be done with macros that contain if? 
[Recently created (on 3/00) and added the last three paragraphs, including the link showing why we don't use do {...} while (false) (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]
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:
#define MYMACRO(a,b) \
if (xyzzy) asdf()
This will cause big problems if someone uses that macro in an if statement:
if (whatever)
MYMACRO(foo,bar);
else
baz;
The problem is that the else baz nests with the wrong if: the compiler sees this:
if (whatever)
if (xyzzy) asdf();
else baz;
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:
#define MYMACRO(a,b) \
if (xyzzy) asdf(); \
else
Now the compiler will see a balanced set of ifs and elses:
if (whatever)
if (xyzzy)
asdf();
else
; // that's an empty statement
else
baz;
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:
if (whatever)
MYMACRO(foo,bar); // right: there is a ; after MYMACRO(...)
else
baz;
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 ]
[34.2] What should be done with macros that have multiple
lines? 
[Recently created (on 3/00) and changed "if (1)..." to "if (true)..." and "do...while (0)" to "do...while (false)" (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]
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:
#define MYMACRO(a,b) \
statement1; \
statement2; \
... \
statementN;
This can cause problems if someone uses the macro in a context that demands a
single statement. E.g.,
while (whatever)
MYMACRO(foo, bar);
The naive solution is to wrap the statements inside {...}, such as this:
#define MYMACRO(a,b) \
{ \
statement1; \
statement2; \
... \
statementN; \
}
But this will cause compile-time errors with things like the following:
if (whatever)
MYMACRO(foo, bar);
else
baz;
since the compiler will see a } ; else which is illegal:
if (whatever)
{
statement1;
statement2;
...
statementN;
}; // ERROR: { } cannot have a ; before an else
else
baz;
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:
#define MYMACRO(a, b) \
do { \
statement1; \
statement2; \
... \
statementN; \
} while (false)
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:
if (whatever)
MYMACRO(foo, bar); // The ; is added here
else
baz;
This will expand to the following (note that the ; added by the user goes
after (and completes) the "} while (false)" part):
if (whatever)
do {
statement1;
statement2;
...
statementN;
} while (false);
else
baz;
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):
#define MYMACRO(a, b) \
if (true) { \
statement1; \
statement2; \
... \
statementN; \
} else
Now the code will expand into this (note the balanced set of ifs and elses):
if (whatever)
if (true) {
statement1;
statement2;
...
statementN;
} else
; // that's a null statement
else
baz;
[ Top | Bottom | Previous section | Next section ]
[34.3] What should be done with macros that need to
paste two tokens together? 
[Recently created (on 3/00). Click here to go to the next FAQ in the "chain" of recent changes.]
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:
#define MYMACRO(a) \
/*...*/ a ## Tmp /*...*/
However (and I don't remember whether the following is a workaround for some
buggy compilers or whether it's a rule in the language, but regardless it's a
good idea), you are better off with a double layer of indirection when you use
##. Basically you ought to create a special macro for "token pasting"
such as this:
#define name2(a,b) name2_hidden(a,b)
#define name2_hidden(a,b) a ## b
Then replace your use of a ## Tmp with name2(a,Tmp):
#define MYMACRO(a) \
/*...*/ 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:
#define name3(a,b,c) name3_hidden(a,b,c)
#define name3_hidden(a,b,c) a ## b ## c
[ Top | Bottom | Previous section | Next section ]
[34.4] Why can't the compiler find my header file in
#include "c:\test.hpp" ?
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:
#if 1
#include "/version/next/alpha/beta/test.hpp" // RIGHT!
#else
#include "\version\next\alpha\beta\test.hpp" // WRONG!
#endif
Note that you should use forward slashes ("/") on all your
filenames, not just on your #include files.
[ Top | Bottom | Previous section | Next section ]
[34.5] What are the C++ scoping rules for for loops? 
[Recently because the scoping rules for for loops are no longer "new" (thanks Stan Brown), rewote the FAQ (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]
Yep.
The following code used to be legal, but not any more, since i's scope is now
inside the for loop only:
for (int i = 0; i < 10; ++i) {
// ...
if ( /* something weird */ )
break;
// ...
}
if (i != 10) {
// We exited the loop early; handle this situation separately
// ...
}
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 ]
[34.6] Why can't I overload a function by its return
type?
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 ]
[34.7] What is "persistence"? What is a "persistent object"?
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 ]
[34.8] Why is floating point so inaccurate? Why doesn't this
print 0.43? 
[Recently changed so it uses new-style headers and the std:: syntax (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]
#include <iostream>
int main()
{
float a = 1000.43;
float b = 1000.0;
std::cout << a - b << '\n';
}
(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):
seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
01000100011110100001101110000101
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 ]
[34.9] How can I create two classes that both know about each other?
Use a forward declaration.
Sometimes you must create two classes that use each other. This is called a
circular dependency. For example:
class Fred {
public:
Barney* foo(); // Error: Unknown symbol 'Barney'
};
class Barney {
public:
Fred* bar();
};
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":
class Barney;
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 ]
[34.10] What special considerations are needed when forward
declarations are used with member objects?
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,
class Fred; // Okay: forward declaration
class Barney {
Fred x; // Error: The declaration of Fred is incomplete
};
class Fred {
Barney* y;
};
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:
class Barney; // Okay: forward declaration
class Fred {
Barney* y; // Okay: the first can point to an object of the second
};
class Barney {
Fred x; // Okay: the second can have an object of the first
};
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 ]
[34.11] What special considerations are needed when forward
declarations are used with inline functions?
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,
class Fred; // Okay: forward declaration
class Barney {
public:
void method()
{
x->yabbaDabbaDo(); // Error: Fred used before it was defined
}
private:
Fred* x; // Okay: the first can point to an object of the second
};
class Fred {
public:
void yabbaDabbaDo();
private:
Barney* y;
};
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:
class Barney; // Okay: forward declaration
class Fred {
public:
void yabbaDabbaDo();
private:
Barney* y; // Okay: the first can point to an object of the second
};
class Barney {
public:
void method()
{
x->yabbaDabbaDo(); // Okay: Fred is fully defined at this point
}
private:
Fred* x;
};
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 ]
[34.12] Why can't I put a forward-declared class in a std::vector<>? 
[Recently changed so it uses new-style headers and the std:: syntax (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]
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,
class Fred; // Okay: forward declaration
class Barney {
std::vector<Fred> x; // Error: the declaration of Fred is incomplete
};
class Fred {
Barney* y;
};
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:
class Fred; // Okay: forward declaration
class Barney {
std::vector<Fred*> x; // Okay: Barney can use Fred pointers
};
class Fred {
Barney* y;
};
Another solution to this problem is to reverse the order of the classes so
Fred is defined before Barney:
class Barney; // Okay: forward declaration
class Fred {
Barney* y; // Okay: the first can point to an object of the second
};
class Barney {
std::vector<Fred> x; // Okay: Fred is fully defined at this point
};
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 ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Jul 10, 2000
|