Monday Jul 14, 2008

I have to admit that when I was writing Professional C++ I never imagined this. A couple weeks ago, I received a few copies from my agent, so thought I’d take some pictures of the four different editions I’ve had the pleasure of holding in my hands.

Left to right: US/Canadian/UK edition, Russian edition, Indian (English-language) Edition, Chinese Edition

Bottom to top: US/Canadian/UK edition, Russian edition, Chinese Edition, Indian (English-language) Edition

Thursday Aug 09, 2007

A co-worker recently asked me to look at an interesting C++ compilation problem. The constructor for one of her classes refused to compile until she simply changed one of the parameter names! Why should the parameter name matter?

Here's a much-simplified version of the class, with a trivial main(), removing proprietary information (this code isn't yet open-source).


#include
#include
#include

class myclass {
public:
   myclass(char *s_net);
};

myclass::myclass(char *s_net)
{
   // do stuff
}

int main()
{
   // do stuff
}

The Sun Studio 10 compiler gives the following errors when attempting to compile the translation unit:


"test.cc", line 7: Error: No direct declarator preceding "(".
"test.cc", line 10: Error: myclass is not a static data member.
"test.cc", line 10: Error: Badly formed expression.

Changing the name of the only parameter to the myclass constructor to something else like net allows the code to compile with no errors.

What's going on?

It turns out that s_net is defined in netinet/in.h as follows


#define s_net _S_un._S_un_b.s_b1 /* OBSOLETE: network */

So when the preprocessor makes its substitutions prior to the actual compilation, the symbol s_net is replaced with something like _S_un._S_un_b.s_b1. (There are actually a few more substitutions, as we'll see momentarily). We can see this ourselves by using the -P option to CC to run the test program through just the preprocessor. This gives, in part:


class myclass {
public :
myclass ( char * S_un . S_un_b . s_b1 ) ;
} ;

myclass :: myclass ( char * S_un . S_un_b . s_b1 )
{

}

That obviously won't compile!

This example demonstrates two problems. The first is the use of globals, specifically #defines. Who would expect a generic symbol like s_net to be #defined in a standard header file? It would be bad enough if it were simply a global variable, but that at least would probably not have caused a problem in this case, because the use of s_net in the constructor would hide the global s_net. However, the preprocessor actually search/replaces the #define term so that the compiler never gets a chance to see s_net as the parameter name in the constructor.

The second problem is that the preprocessor does this substitution and other modifications such that the code for which the compiler is giving a warning is not the code that you see when you look at your source file. This can make debugging difficult.

Moral of the story: Use the preprocessor judiciously!

Thursday May 17, 2007

Why Do I Need Smart Pointers?

Working with dynamically allocated memory in languages like C++ can be difficult. If you allocate some memory and forget to free it, you get a memory leak. But if you free it more than once you get memory corruption. Not surprisingly, memory management errors are a significant source of bugs in many C++ programs.

Now imagine if you could dynamically allocate memory and use it in your program without ever worrying about freeing it! No, I’m not suggesting you switch to Java. You can obtain this ease-of-use in C++ too, simply by using smart pointers.

[Read More]

Friday May 11, 2007

The following tutorial is adapted from Professional C++ Chapter 11, "Writing Generic Code with Templates."

What are Templates?

Most computer languages, including C++, provide support for procedures or functions that allow you to write algorithms that are independent of specific values and can thus be reused for many different values. For example, the sqrt() function in C and C++ calculates the square root of a value supplied by the caller. A square root function that calculated only the square root of one number, like four, would not be particularly useful! The sqrt() function is written in terms of a parameter, which is a stand-in for whatever value the caller passes. Computer scientists say that functions parameterize values.

Templates (called Generics in Java) take the concept a step further to allow you to parameterize on types as well as values. Recall that types in C++ include primitives such as int and double, as well as user-defined classes. With templates, you can write code that is independent not only of the values it will be given, but of the types of those values as well! For example, instead of writing separate queue classes to store ints, Packets, or any other object, you can write one queue class definition that can be used for any of those types.

C++ supports both class templates and function templates. This tutorial will cover the basics of class templates.

[Read More]

Monday Apr 30, 2007

I strongly disliked writing when I was in school. In fact, it probably wouldn’t be too strong to say I hated it. In college I actively avoided classes involving writing assignments. So I sometimes find it hard to believe that not only do I enjoy writing now, I was the lead author of an 838-page book on C++.

My co-author, Scott Kleper, wrote a great post about the process of writing Professional C++, so I won’t dwell on that here. Instead, I’d like to introduce a few of the features that we feel sets Professional C++ apart from other programming books. In future posts I’ll cover some of the particularly interesting aspects of the C++ language and C++ software engineering.

Scott and I believe that teaching C++ programming involves two things: teaching C++ and teaching programming. To that end, we tried to present the C++ syntax and feature-set in the larger context of software engineering and object-oriented methodologies. Specifically,


  • Emphasis on design, including object-oriented design, design themes of abstraction and reuse, design techniques such as smart pointers, and design patterns such as the singleton pattern.

  • Discussion of software engineering methodologies such as extreme programming.

  • Focus on style. We include an entire chapter on C++ style, and call attention to good stylistic practices throughout the book.

  • Inclusion of debugging and testing strategies. We devote over 50 pages to testing and debugging.

  • Discussion of “extra” topics such as writing efficient C++ code, mixing C++ with other languages, and using distributed objects.


In addition, we of course cover all the "usual" C++ stuff: objects, classes, inheritance, memory management, templates, operator overloading, the STL, I/O, exceptions, etc. Watch this space for a tutorial on smart pointers, coming soon!

This blog copyright 2009 by Nicholas Solter