Introduction

So you have been away from C++ more than you care to remember? Have you lost track of all changes that happened to C++ since you learned how to use it? Don't know that C++ is a standard language since 1998?

Then this column is for you. My purpose here is to to describe most of the things that ocasional C++ users might find strange when they get their hands on compilers that are more close to the standard that the ones they usually use.

Since I can't talk about everything, I advise you to look for more information in the C++ standard, or in the third edition of the C++ Programming Language book.

Or in the sites indicated at the bottom of the article.

C++ got the type bool

Many C++ programmers don't know that C++ has the type bool, many still use the types int or char, and macros to replicate the type bool. But C++ does have this type so don't fell strange when you find code like the one below.

bool done = false;

while (!done) {
  // do some stuff
  done = are_we_done ();
}

Header files changes

Header files lost the .h suffix

What was wrong with the current naming covention for header files? You might ask. Basically the problem is not directly related with the naming convention but with something that now makes the header files behave differently.

In C++ you can use namespaces, which are a way to put classes, types, functions, and everything else 1 under a common namespace. I will explain this latter, but the important thing to note here is that the ANSI/ISO commite made use of this language feature to put the library under the namespace std.

Now imagine that you have just installed your new C++ compiler and decide to try to compile with it some older code that you have lying around on your computer.

It would be very strange if the compiler fail over complaining about not finding symbols that should be standard. But you shouldn't rely on having the old includes in your new compiler because they were deprecated, and are provided just as a way to ease the porting of the code, to make it up to date with the standard.

Another reason for changing the names for the standard headers is because some standard in naming the files had to be achived. Previously the compilers used the extensions .hxx, .h, .hpp, etc. And besides the headers files can be binary files, the standard doesn't force them to be text files. So they had to be invalidaded and a new way to reference to them be created.

C Header files lost the .h suffix and got a c prefix

Due to the same reasons as described in the previous point, header files that C++ got from C, lost their .h suffix and also gained a c prefix.

Now, instead you making a #include <stdlib.h>, you should use #include <cstdlib>, instead.

Once again the older convention for names of header files is deprecated and provided just as a way to ease the porting of the code.

C++ got namespaces

Namespaces are a way to put all your code under a common identifier. You can think of it as packages in Java, modules in Modula-2, units in Delphi, and so on. It's not a full module support because there isn't the dependency notion that module systems usually have. However it's a great way to organize your code.

So how does it work? You just have to put your code inside a namespace like it was a struct or a class. For example:

namespace my_namespace {
 typedef int a_type;

 class some_class {
  // ...
 };
}

This declares the namespace my_namespace with two declarations inside. A typedef and a class. If you want to refer to some of that identifiers, outside the namespace, you have to prefix them with the namespace name. So if you want to refer to a_type, you would use the my_namespace::a_type syntax.

But if you don't like typing the namespace name to access all the stuff that is declared there, you can bring them to global scope. You can bring all of them by a using directive or just bring the ones you want with a using declaration. For example:

// import the type a_type by use of a 'using declaration'
using my_namespace::a_type;

// Declare a variable of the type a_type
a_type some_global_var;

A using directive is great when coding the implementation of the stuff that was declared in the namespace, for example:

// import all the namespace identifiers by use of a 'using directive'
using namespace my_namespace;

some_class::some_class ()
{
  a_type a_var;
  //...
}

Without namespaces, that would be:

my_namespace::some_class::some_class ()
{
  my_namespace::a_type a_var;
  //...
}

So to avoid conflict with user identifiers, the ANSI/ISO group decided that the standard library should be under the std namespace.

Now to answer why the header files changed. The old ones just include the new ones and bring all the identifiers to global namespace. If you use the new ones, you must use the std prefix just like the my_namespace in the examples presented before. This is why if the comitee decided to keep the old header files, or else all your code would break.

Please note that this affects C and C++ headers. The new headers provide their symbols under the std namespace.

new now throws

Since C++ has exceptions we should make use of them and this was what ANSI/ISO thought. So if new fails to allocate memory instead of returning 0 as it did previously, it now throws a bad_alloc exception.

If you want the old behaviour, you must compile your code with exceptions disabled, which can give problems when liking with code that uses exceptions. Or you can use the placement new giving
nothrow as argument.

For example, if you want this code to continue to behave the same way,

char *buff = new char [1000];
if (!buff)
  // Do something

You must change the way new is called,

char *buff = new(nothrow) char [1000];
if (!buff)
  // Do something

Constructors can be explicit

Have you ever tried to find why a compiler was allowing a conversion between different classes and no conversion operators between them did exist? This usually happens if the destination class has a constructor that receives the source class and uses a compiler generated operator=(), so the compiler generates a temporary and uses it to assign the source class to the destination class. But if you didn't want this to happen?

In C++ there is a way prevent this situation. If you declare your constructor as explicit, that constructor can only be invoked in variable declarations. For example,

class SomeClass {
public:
  explicit SomeClass (const OtherClass &arg);
  // ...
};

void a_func ()
{
  OtherClass var1;
  SomeClass var2 (var1); // Ok
  OtherClass var3;

  var2 = var3; // Error, the constructor won't be called

}

Data members can be mutable

Have you ever declared a const member function only to discover that you can't modify data members inside the method? But I hear you say "that's the way it's supposed to work"! Yes, you are right. But there are some situations where this funcionality is needed.

Suppose that you want to implement some scheme of reference counting in you class. And you need to modify the reference value inside all member functions. You can't do that inside const
member functions. So what would you do? Drop the consteness from the member function? Unfortunaly that was the soluction most of the time, until the language got support for mutable data members.

With the support of mutable, you just have to declare your data member as mutable and you will be able to modify the data member from a const member function. For example,

class MutableDemo {
  int ref;
  mutable int mut_ref;
public:
  int get_something () const {
    ref = 2;     // Error! Can't assign to data member
    mut_ref = 2; // Ok. It is mutable
  }
};

IOStreams suffered some changes

If you see very strange messages with templates, related to your use of iostreams, don't despair.

The iostreams were recodified and now make intensive use of templates, so much for only pay for what you use. It might seem bat, but it isn't. After all, to make good use of C++ you should use STL. Which means that you will be using templates, so no problem arises with IOStreams just because they use templates.

Ok, you don't agree with me, but IOStreams are powerfull an flexible, so I think it's worth the price. :)

The other big change was that some methods have disapereed, others have appered. But most of them are private/protected, so if you haven't extended any of the iostreams classes, you shouldn't have any problem.

One improvement that you should be aware is that iostreams now fully support locales by using a set of classes know as locales and facets.

So if you develop code that needs to use locale information, maybe this will help you.

Templates modifications

typename instead of class

Instead of using the class keyword to denote type arguments in templates, you can use the typename keyword.

This keyword appeared when the need to help the compiler when processing templates appeared. Sometimes it's hard for it to know the correct kind of template argument, for example:

template <class T>
class TemplateClass {
public:
  typename T::a_type a;
};

The compiler will know that a_type is a type and not other kind of identifier because we tell it so. Otherwise it might not be able to deduce what a_type represented.

Normal classes can have member templates

In C++ you can declare three different kind of templates:

Member templates were added almost in the end of the standardization process and they allow the declaration of member functions as templates.

So instead of declaring a whole class as template just because you need to use some member function as a template, you can declare just that member function as a template. For example,

class AClassWithAMemberFunc {
public:

  template <class T>
  int do_something (const T &arg);
};

Templates can be exported

If you make use of templates in your code, you are well aware of the pain that is to put all the template code in header files and watch it being parsed all the time. In C++ exists a way to
write you code in implementation files (.cpp) and you only need to write the template interface in the header file. For that you have to export the template.

As an example lets create a template function, swap (), that uses the export keyword.

// in swap.h
template template <class T> void swap (T &left, T &right);


// in swap.cpp
// note the use of export
export template <class T>
void swap (T &left, T &right)
{
  T temp = right;
  right = left;
  left = temp;
}

C-style casts are bad

Yes that's true, your favorite casts are considered evil and are expected to disapeer from the language sometime in the future. These casts are confusing and the compiler doesn't make any check to the way casts are performed. So new ways of making casts were created, and they are:

?: changed semantics

The condicional operator has changed it's semantics
but it won't probably affect you. The following
code,

exp ? a : b + 1

used to be evaluated as,

(exp ? a : b) + 1

but now it is evaluated as,

exp ? a : (b + 1)

So unless you made use of that kind of precedence, the
change in semantics won't affect you. And to be honest,
this is the correct way to handle the operator.

Further information

For better information about what was discussed here, please take
a look at the following sites:

Acknowledges

I would like to thank to the following people for their
input to this document:

Bibliography


  1. Macros don't count here.