Skip to content

Using the new C++

July 15, 2011

As the new C++ Standard (known to most as C++0x) edges towards final acceptance, more and more programmers are using its new features in their day-to-day code. In this article, I’d like to recount some of my experiences in actually using four of  those features in my own code. Please note that this is not a tutorial on C++0x, though I will give brief explanations of  the features I discuss, nor is it intended as a technical critique of those features.

If you want to try these features out yourself, they are all available in version 4.5 and later of the GCC C++ compiler. If you are on Windows, see this article for instructions on how to download and install such a compiler – if you are on Linux you probably already have it. You will have to tell the compiler you are using C++0x code using the –std command line option:

g++ -std=c++0x mystuff.cpp

Type deduction with auto

The first feature I want to look at is the re-purposing of the C++ auto keyword. This keyword has been around in both C and C++ from the very earliest times, when C compilers required you to say things like this:

int f() {
    auto int x;
}

In other words, the auto keyword was required to create variables on the stack. This has not been needed since those very early C compilers, but has hung around for compatibility reasons. As no modern code uses it, the C++ Committee felt justified in reusing it to create variables who’s type is determined by the compiler, rather than directly by the programmer. In C++ you can now say:

int f() {
    auto x = 42;
}

The compiler will look at the type of the expression being used to initialise x, see that it (in this case)  the expression evaluates to an int, and will make the variable x an int, as if you had said:

int x = 42;

This ability is not particularly useful for declaring ints, but can be handy when using templates. Consider this code:

map <int,string> Messages;

void Dump( ostream & os, const map <int,string> & m ) {
    map<int,string>::const_iterator it = m.begin();
    while( it != m.end() ) {
        os << it->first << " = " << it->second << "\n";
        ++it;
    }
}

Declaring the iterator it requires a lot of typing on the keyboard, and is irritatingly easy to get wrong. The new C++ allows us to write the much simpler:

auto it = m.begin();

The compiler can deduce what type it must be, because it knows what type m is, and what type m’s begin() function returns – in this case it’s the const version of begin(), which returns a const_iterator.

I do use auto in my own code, but I have a couple of problems with it. Firstly, with  code like this:

auto it = m.begin();

the compiler may know what the type of the iterator it is, but it is far from clear to me! I have to think what type m is and then what type begin() returns. In the old code, I said explicitly what the type was, or at least what I wanted it to be, and if I got it wrong the compiler told me about it. Although type deduction has made the code easier to write, I’m far from convinced it has made it easier to understand. I suspect that we will be producing C++ programmers who simply do not know what the types of their auto variables are (would they know that it is a const_iterator, for example), which cannot be a good a thing.

The second issue I have with auto is related to the first. In fact, nobody (or at least nobody sensible) writes code like that in my motivating example above. They instead write:

typedef map <int,string> MsgMap;
MsgMap Messages;

void Dump( ostream & os, const MsgMap & m ) {
    MsgMap::const_iterator it = m.begin();
    while( it != m.end() ) {
        os << it->first << " = " << it->second << "\n";
        ++it;
    }
}

In other words, instead of writing out the full type of the map everywhere, you should create a typedef for it. This makes not only the iterator much easier to declare (and easy to see the type of when reading code) but also the function parameter is simpler and clearer too, and type deduction does not work for function parameters. It seems to me that this style of programming is better practice than that which may be fostered by the indiscriminate use of auto, and if I have to maintain code, I know which one I’d rather have to deal with.

Bottom line – I do use auto in my own code (there are several other examples in this article), but I worry about it!

Initialiser Lists

The second new feature of C++0x I want to look at is one that I’m much keener on. In both C and C++ you have always been able to say things like this:

int a[] = { 1, 2, 3, 4 };

and have your array or struct, or array of structs, correctly initialised. This has always been much harder to do for the user-defined types in C++. For example, in “old” C++, you cannot say this:

vector <int> v = { 1, 2, 3, 4 }

In “new” C++, you can and should say these things. You can get much more ambitious too – given the MsgMap type from the previous section, you can do things like this:

MsgMap Messages = {
    { 1, "message #1" },
    { 2, "message #2" }
};

Note that the ability to do this initialisation means that we now can make the map const, and in this case probably that is what we want.

This new initialisation ability is implemented via a template initializer_list<T> which is declared in the new Standard Library header <initializer_list>. Although primarily intended for use with container classes like lists and vectors (which most people won’t be implementing), it can be used in other classes. For example, this class constructs a file-system path from such a list (note somewhat hypocritical use of auto to shorten the code!):

struct Path {
    Path( const initializer_list <string> & ilist ) {
        auto it = ilist.begin();
        while( it != ilist.end() ) {
            path += *it;
            it++;
            if ( it != ilist.end() ) {
                path += '/';
            }
        }
    }
    string path;
};

allowing us to say things like:

const Path p1 = { "some", "path" };
const Path p2 = { GetCurrent(), "temp", ProjectName() };

This feature seems to me to a great addition to the language, and already I can’t see how I ever did without it! It also seems like a perfect example of how to go about extending a language like C++.

Class enums

The enum has long been a problematic feature of C++. People often say that their use is indicative of a non-OO approach to problems. Well, so it may be, but so what – C++ is a multi-paradigm language, and use of enums is part of the procedural paradigm it supports. The big trouble with enums is their weird scoping rules. For example:

enum Color { Red, Blue, Green };
enum TrafficLight { Red, Amber, Green };

won’t work in “old” C++ because the Reds and Greens  are names in the same scope – the scope in which the enums were declared. And you can’t get round it like this:

Color c = Color::Red;

because Color does not name a scope. Traditionally, the way round this has been to wrap enums in a class, but that simply causes problems inside the class. What is really needed is for enums to create a  scope, and that’s what class enums do:

enum class Color { Red, Blue, Green };
enum class TrafficLight { Red, Amber, Green };

And we can now refer to Color::Red or TrafficLight::Red. Why enums didn’t always work this way is one of life’s minor mysteries (OK, I know it isn’t really – C compatibility is the reason), but it’s good that this has been fixed, and I now use class enums in all my new code.

Standard Library Enhancements

The last feature of the new C++ that I’ve been making a lot of use of is not so much a single feature as enhancements to the C++ Standard Library (or what ome misguided folk still insist in referring to as “the STL”).

The first of these is unique_ptr, which is the replacement for the old auto_ptr class, which has been deprecated. Deprecation means that it may be removed from future C++ standards without warning – however, this is extremely unlikely to ever happen; it will probably continue as a deprecated feature throughout eternity!

The unique_ptr class allows you to use single-ownership smart pointers in containers, because when the containers are resized it does not (unlike auto_ptr) delete the object it points to. The ability to do this actually depends on a couple of new language features I haven’t mentioned here – it was in fact not possible to write template classes like unique_ptr before C++0x. This means that we can now write containers like:

vector <unique_ptr<SomeClass>> v1;

and have them manage the lifetimes of the dynamically created objects they contain pointers to, without the overhead of things like shared_ptr. Note that you still cannot copy unique_ptr objects so code like this:

vector <unique_ptr<SomeClass>> v2( v1 );

will give you an error message. The message (for GCC at least) is typically over-verbose, but understandable if you take the trouble to read it. In any case, I’m now retro-fitting unique_ptr to my old code, mostly so as to avoid “deprecation” messages regarding auto_ptr.

In passing, note the double-angle bracket >> in the above code – this used to be an error in “old” C++, but is allowed in the “new” version.

Another Standard Library class I’ve found useful is the new array type. This is intended as a drop in replacement for C-style arrays. For example:

int main() {
    int a1[10];
    array <int,10> a2;
}

Both these statements under the hood do exactly the same thing – they create an array on the stack, with no dynamic memory allocation. The latter however has numerous advantages over the former – particularly it has a size() member function so that you can pass it to functions and still be able to find out how big it is. It’s not that my own code is littered with arrays (it isn’t), but at last we have something we can point new users (and misguided worriers about “performance”)  at, rather than telling them to use the conceptually more complex vector class.

The last Standard Library enhancement I use in my own code is that for generating random numbers, defined in <random>. For years, C++ users have had to either use the old C rand/srand combination, which frankly doesn’t work, write our own PRNGs (eek!) or depend on external libraries like Boost (the path taken by most of us). At last, C++ has proper PRNG features, based on those in the Boost library. Here’s an example of generating six throws of a six sided dice:

#include <functional>
#include <iostream>
#include <random>
using namespace std;

int main() {
    mt19937 rng;                
    uniform_int_distribution<> one_to_six( 1, 6 );
    auto dice = bind( one_to_six, rng );
    for ( int i = 0; i < 6; i++ ) {
        int n  = dice();
        cout << n << endl;
    }
}

The minor one grouch I have about the new random number generator stuff is that it would have been nice to maintain a bit more compatibility with Boost.

Conclusion

That about wraps up my use of new C++0x features. There are several things that I don’t really use, such as lambda’s (never really grabbed me) and the kind of for-loop (not available yet in the version of GCC I use), and there are lots of other features that can only really be of interest to container library authors or the performance-obsessed. For a good overview of the new features, take a look at Bjarne Stroutrup’s C++0X FAQ. For a summary of GCC compliance with the new Standard, see this page.

Advertisements

From → c++, devtools, linux, windows

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: