[39] Miscellaneous technical issues  Updated! 
(Part of C++ FAQ Lite, Copyright © 1991-2006, Marshall Cline, cline@parashift.com)


FAQs in section [39]:


[39.1] How do I convert a value (a number, for example) to a std::string?

There are two easy ways to do this: you can use the <cstdio> facilities or the <iostream> library. In general, you should prefer the <iostream> library.

The <iostream> library allows you to convert pretty much anything to a std::string using the following syntax (the example converts a double, but you could substitute pretty much anything that prints using the << operator):

 // File: convert.h
 #include <iostream>
 #include <sstream>
 #include <string>
 #include <stdexcept>
 
 class BadConversion : public std::runtime_error {
 public:
   BadConversion(const std::string& s)
     : std::runtime_error(s)
     { }
 };
 
 inline std::string stringify(double x)
 {
   std::ostringstream o;
   if (!(o << x))
     throw BadConversion("stringify(double)");
   return o.str();
 }

The std::ostringstream object o offers formatting facilities just like those for std::cout. You can use manipulators and format flags to control the formatting of the result, just as you can for other std::cout.

In this example, we insert x into o via the overloaded insertion operator, <<. This invokes the iostream formatting facilities to convert x into a std::string. The if test makes sure the conversion works correctly — it should always succeed for built-in/intrinsic types, but the if test is good style.

The expression o.str() returns the std::string that contains whatever has been inserted into stream o, in this case the string value of x.

Here's how to use the stringify() function:

 #include "convert.h"
 
 void myCode()
 {
   double x = 
...;
   
...
   std::string s = "the value is " + stringify(x);
   
...
 }

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.2] How do I convert a std::string to a number?

There are two easy ways to do this: you can use the <cstdio> facilities or the <iostream> library. In general, you should prefer the <iostream> library.

The <iostream> library allows you to convert a std::string to pretty much anything using the following syntax (the example converts a double, but you could substitute pretty much anything that can be read using the >> operator):

 // File: convert.h
 #include <iostream>
 #include <sstream>
 #include <string>
 #include <stdexcept>
 
 class BadConversion : public std::runtime_error {
 public:
   BadConversion(const std::string& s)
     : std::runtime_error(s)
     { }
 };
 
 inline double convertToDouble(const std::string& s)
 {
   std::istringstream i(s);
   double x;
   if (!(i >> x))
     throw BadConversion("convertToDouble(\"" + s + "\")");
   return x;
 }

The std::istringstream object i offers formatting facilities just like those for std::cin. You can use manipulators and format flags to control the formatting of the result, just as you can for other std::cin.

In this example, we initialize the std::istringstream i passing the std::string s (for example, s might be the string "123.456"), then we extract i into x via the overloaded extraction operator, >>. This invokes the iostream formatting facilities to convert as much of the string as possible/appropriate based on the type of x.

The if test makes sure the conversion works correctly. For example, if the string contains characters that are inappropriate for the type of x, the if test will fail.

Here's how to use the convertToDouble() function:

 #include "convert.h"
 
 void myCode()
 {
   std::string s = 
...a string representation of a number...;
   
...
   double x = convertToDouble(s);
   
...
 }

You probably want to enhance convertToDouble() so it optionally checks that there aren't any left-over characters:

 inline double convertToDouble(const std::string& s,
                               bool failIfLeftoverChars = true)
 {
   std::istringstream i(s);
   double x;
   char c;
   if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
     throw BadConversion("convertToDouble(\"" + s + "\")");
   return x;
 }

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.3] Can I templatize the above functions so they work with other types?

Yes — for any types that support iostream-style input/output.

For example, suppose you want to convert an object of class Foo to a std::string, or perhaps the reverse: from a std::string to a Foo. You could write a whole family of conversion functions based on the ones shown in the previous FAQs, or you could write a template function so the compiler does the grunt work.

For example, to convert an arbitrary type T to a std::string, provided T supports syntax like std::cout << x, you can use this:

 // File: convert.h
 #include <iostream>
 #include <sstream>
 #include <string>
 #include <typeinfo>
 #include <stdexcept>
 
 class BadConversion : public std::runtime_error {
 public:
   BadConversion(const std::string& s)
     : std::runtime_error(s)
     { }
 };
 
 template<typename T>
 inline std::string stringify(const T& x)
 {
   std::ostringstream o;
   if (!(o << x))
     throw BadConversion(std::string("stringify(")
                         + typeid(x).name() + ")");
   return o.str();
 }

Here's how to use the stringify() function:

 #include "convert.h"
 
 void myCode()
 {
   Foo x;
   
...
   std::string s = "this is a Foo: " + stringify(x);
   
...
 }

You can also convert from any type that supports iostream input by adding this to file convert.h:

 template<typename T>
 inline void convert(const std::string& s, T& x,
                     bool failIfLeftoverChars = true)
 {
   std::istringstream i(s);
   char c;
   if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
     throw BadConversion(s);
 }

Here's how to use the convert() function:

 #include "convert.h"
 
 void myCode()
 {
   std::string s = 
...a string representation of a Foo...;
   
...
   Foo x;
   convert(s, x);
   
...
   
...code that uses x...
 }

To simplify your code, particularly for light-weight easy-to-copy types, you probably want to add a return-by-value conversion function to file convert.h:

 template<typename T>
 inline T convertTo(const std::string& s,
                    bool failIfLeftoverChars = true)
 {
   T x;
   convert(s, x, failIfLeftoverChars);
   return x;
 }

This simplifies your "usage" code some. You call it by explicitly specifying the template parameter T:

 #include "convert.h"
 
 void myCode()
 {
   std::string a = 
...string representation of an int...;
   std::string b = 
...string representation of an int...;
   
...
   if (convertTo<int>(a) < convertTo<int>(b))
     
...;
 }

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.4] What should be done with macros that contain if?

Ideally you'll get rid of the macro. Macros are 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).

Nonetheless, even though macros are evil, sometimes they are the lesser of the other evils. When that happens, read this FAQ so you know how to make them "less bad," then hold your nose and do what's practical.

Here's a naive solution:

 #define MYMACRO(a,b) \                (Bad)
     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) \                (Good)
     if (xyzzy) asdf(); \
     else (void)0

(The (void)0 causes the compiler to generate an error message if you forget to put the ; after the 'call'.)

Your usage of that macro might look like this:

 if (whatever)
     MYMACRO(foo,bar);
 else                ^
—this ; closes off the else (void)0 part
     baz;

which will get expanded into a balanced set of ifs and elses:

 if (whatever)
     if (xyzzy)
         asdf();
     else
         (void)0;
 else    ^^^^^^^^
—that's a do-nothing statement
     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.

There is another approach that old-line C programmers will remember:

 #define MYMACRO(a,b) \                (Okay)
     do { \
       if (xyzzy) asdf(); \
     } while (false)

Some people prefer the do {...} while (false) approach, though if you choose to use that, be aware that it might cause your compiler to generate less efficient code. Both approaches cause the compiler to give you an error message if you forget the ; after MYMACRO(foo,bar).

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.5] What should be done with macros that have multiple lines?

Answer: Choke, gag, cough. Macros are evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4. Kill them all!! (Just kidding.)

Seriously, sometimes you need to use them anyway, and when you do, read this to learn some safe ways to write a macro that has multiple statements.

Here's a naive solution:

 #define MYMACRO(a,b) \                (Bad)
     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) \                (Bad)
     { \
         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: can't have }; before else
 else
     baz;

One solution is to use a do { <statements go here> } while (false) pseudo-loop. This executes the body of the "loop" exactly once. The macro might look like this:

 #define MYMACRO(a, b) \                (Okay)
     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;

This is an acceptable approach, however some C++ compilers refuse to inline-expand any function that contains a loop, and since this looks like a loop, those compilers won't inline-expand any function that contains it. Do some timing tests with your compiler to see; it might be a non-issue to you (besides, you might not be using this within an inline function anyway).

A possibly better solution is to use if (true) { <statements go here> } else (void)0

 #define MYMACRO(a, b) \                (Best)
     if (true) { \
         statement1; \
         statement2; \
         
... \
         statementN; \
     } else
         (void)0

The preprocessor will expand the usage into the following (note the balanced set of ifs and elses):

 if (whatever)
     if (true) {
         statement1;
         statement2;
         
...
         statementN;
     } else
         (void)0;
 else    ^^^^^^^^
—that's a do-nothing statement
     baz;

The purpose of the strange (void)0 at the end is to make sure you remember to add the ; just after any usage of the macro. For example, if you forgot the ; like this...

 foo();
 MYMACRO(a, b)   
 bad news: we forgot the ;
 bar();
 baz();

...then the preprocessor would produce this...

 foo();
 if (true) {
     statement1; \
     statement2; \
     
... \
     statementN; \
 } else
     (void)0 bar();   
 fortunately(!) you'll get a compile-time error-message here
 baz();

...which would result in a compile-time error-message. That error-message a lot better than the alternative: without the (void)0, the compiler would silently generate the wrong code, since the bar() call would erroneously be on the else branch of the if.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.6] What should be done with macros that need to paste two tokens together?  Updated! 

[Recently capitalized macro name2() to NAME2() to prevent name-collisions (in 10/05). Click here to go back to the beginning of 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 you need a double layer of indirection when you use ##. Basically you need to create a special macro for "token pasting" such as:

 #define NAME2(a,b)         NAME2_HIDDEN(a,b)
 #define NAME2_HIDDEN(a,b)  a ## b

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):

 #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

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.7] Why can't the compiler find my header file in #include "c:\test.h" ?

Because "\t" is a tab character.

You should use forward slashes ("/") rather than backslashes ("\") in your #include filenames, even on operating systems that use backslashes such as DOS, Windows, OS/2, etc. For example:

 #if 1
   #include "/version/next/alpha/beta/test.h"    
// RIGHT!
 #else
   #include "\version\next\alpha\beta\test.h"    
// WRONG!
 #endif

Note that you should use forward slashes ("/") on all your filenames, not just on your #include files.

Note that your particular compiler might not treat a backslash within a header-name the same as it treats a backslash within a string literal. For instance, your particular compiler might treat #include "foo\bar\baz" as if the '\' chars were quoted. This is because header names and string literals are different: your compiler will always parse backslashes in string literals in the usual way, with '\t' becoming a tab character, etc., but it might not parse header names using those same rules. In any case, you still shouldn't use backslashes in your header names since there's something to lose but nothing to gain.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.8] What are the C++ scoping rules for for loops?

Loop variables declared in the for statement proper are local to the loop body.

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 a 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 altogether 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.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.9] 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.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.10] 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.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.11] 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.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.12] 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.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.13] 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;
 };

There are a number of ways to work around this problem. One workaround would be to define Barney::method() with the keyword inline below the definition of class Fred (though still within the header file). Another would be to define Barney::method() without the keyword inline in file Barney.cpp. A third would be to use nested classes. A fourth would be to reverse the 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.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.14] Why can't I put a forward-declared class in a std::vector<>?

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.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.15] Why do some people think x = ++y + y++ is bad?

Because it's undefined behavior, which means the runtime system is allowed to do weird or even bizarre things.

The C++ language says you cannot modify a variable more than once between sequence points. Quoth the standard (section 5, paragraph 4):

Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.

TopBottomPrevious sectionNext sectionSearch the FAQ ]


[39.16] What's the deal with "sequence points"?

The C++ standard says (1.9p7),

At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.

For example, if an expression contains the subexpression y++, then the variable y will be incremented by the next sequence point. Furthermore if the expression just after the sequence point contains the subexpression ++z, then z will not have yet been incremented at the moment the sequence point is reached.

The "certain specified points" that are called sequence points are (section and paragraph numbers are from the standard):

TopBottomPrevious sectionNext sectionSearch the FAQ ]


E-Mail E-mail the author
C++ FAQ LiteTable of contentsSubject indexAbout the author©Download your own copy ]
Revised Mar 1, 2006