Channels ▼
RSS

C/C++

4 Useful New Features in C++0x


This is the first of a three-part on what's new and important in the C++0x standard. This first article covers features that programmers are apt to use directly; later articles will cover some of the ways in which C++0x simplifies programming for library users and authors

From our experience, we have developed firm opinions about which aspects of programming languages are important to programmers and which ones aren't. As a result, we are going to treat these articles as an opportunity to point out a handful of C++0x features that we think are particularly useful, and to talk about the contexts in which we think those features are best utilized.

Let the Compiler Figure Out Types

A battle has been raging for at least 50 years between languages such as FORTRAN and Algol, which require programmers to say what types they intend their variables to have, and those such as Lisp, that view assigning a value to a variable gives that variable the same type as the value. In C and C++ (until now), the programmer must state the type of every variable:

int answer = 42.1;  # answer is an int, so 42.1 is converted to 42

whereas in Python (for example), a variable has the type of whatever value it was given most recently:

     answer = 42         # answer is now an int
     answer = 42.1       # answer is now a float

In recent decades, a third treatment has crept into some languages: If the compiler can figure out during compilation what type an expression has, why not make it possible to say that a variable has that same type, whatever the type might be? This notion is subtly different from how Lisp and Python do things, because types are figured out during compilation rather than during execution. As a result, there's no way to change the type of a variable after creating it, and the compiler can still generate efficient machine code by using its knowledge of variables' types.

C++ first adopted this idea as part of instantiating template functions:

template <typename T> void swap(T& a, T& b)
{
    T temp = a;
    a = b;
    b = temp;
}

If we have two variables x and y, and we call swap(x, y), the compiler figures out for us the type to associate with T. As a result, we don't need to know the type of x and y in order to call swap(x, y).

In the 1998 and 2003 C++ standards, this kind of type inference was limited to templates. C++0x lets us ask for the same kind of type inference without having to write a template function. We do so by writing auto as part of a variable's type when we define it. For example:

auto answer = 42;    # answer is an int because 42 is an int

says that we want the variable answer to take its type from its initializer. Because each variable is initialized only once, there is still no possibility of changing a variable's type after we have created it.

Why is this feature important? We think the main reason is that it lets us avoid having to figure out the sometimes complicated types that come from using libraries. For example, we can write statements such as:

auto today = get_date();

without having to look in the documentation for get_date to figure out what type it returns.

As a more complicated example, consider the code we have to write in order to look at the elements of a data structure. Suppose we have a variable named word_counts that keeps track of how many times each distinct word appears in a body of text:

map<string, int> word_counts;

We might process this container's elements by writing something like:

for (map<string, int>::const_iterator iter =
         word_counts.begin();
     iter != word_counts.end(); ++iter) {
           process(iter->first, iter->second);
}

Here, we're assuming that we've already written a function named process that does whatever we intend with each word (iter->first) and its associated counter (iter->second).

We can use auto to avoid having to write the type of iter explicitly:

     for (auto iter = word_counts.begin();
          iter != word_counts.end(); ++iter {
                process(iter->first, iter->second);
     }

There is one fine point worth making here: word_counts.begin() yields an iterator that is capable of changing word_counts. In the earlier version, we assigned that iterator to a const_iterator, thereby removing that permission. C++0x containers offer cbegin and cend members that yield const_iterators, so we should really rewrite our example this way:

     for (auto iter = word_counts.cbegin();
          iter != word_counts.cend(); ++iter {
                process(iter->first, iter->second);
     }

More generally, C++0x programmers should use cbegin and cend whenever they intend to iterate through a container without changing its contents.

We think that programmers will be able to use auto to simplify nearly every program they write.

Streamlining Iteration

We can make the previous loop even easier to write. The idiom of using a container's begin and end members to obtain iterators to use as starting and ending values for iteration is so common that C++0x has defined a shorter way to do so, called a range for statement:

     for (const auto& word: word_counts) {
         process(word.first, word.second);
     }

Using a colon in a for statement asks the compiler to iterate through a sequence (word_counts in this example) using begin and end to find the sequence's bounds. The effect is similar to:

auto end_iter = word_counts.end();
for (auto iter = word_counts.begin();
          iter != end_iter; ++iter) {
     const auto& word = *iter;
     process(word.first, word.second);
}

In this code, iter and end_iter represent hidden variables that the compiler generates. In effect, this statement uses each element of the sequence in turn to initialize the variable (word in this example) on the left of the colon. Because we have stated that the type of variable is const auto&, the "initialization" involves binding word to each element, with the promise that we will not use word to change the element's value.

If we omit the & from the variable that we define in a range for statement, it will copy each element of the sequence into our variable. If we omit the const but retain the &, we can use the variable to change the container elements. For example, we can zero all of the counters in word_counts by writing:

     for (auto& word: word_counts)
          word.second = 0; 

Our experience is that programmers who use containers almost always wind up wanting to access their containers' elements sequentially at some point in their programs. This new form of for statement makes this kind of sequential access much easier.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Comments:

Video