Channels ▼
RSS

C/C++

The C++14 Standard: What You Need to Know


In the earlier example on deduced return types, I had a lambda definition that captured a single variable, name, used as the source of a search string in a predicate:

  auto match_name = [&name](const record& r) -> bool {
    return r.name == name;
  };
  auto ii = find_if(people.begin(), people.end(), match_name );

This particular capture gives the lambda access to the variable by reference. Captures can also be performed by value, and in both cases, the use of the variable behaves in a way that fits with C++ intuition. Capture by value means the lambda operates on a local copy of a variable; capture by reference means the lambda operates on the actual instance of the variable from the outer scope.

All this is fine, but it comes with some limitations. I think the one that the committee felt it needed to address was the inability to initialize captured variables using move-only semantics.

What does this mean? If we expect that lambda is going to be a sink for a parameter, we would like to capture the outer variable using move semantics. As an example, consider how you would get a lambda to sink a unique_ptr, which is a move-only object. A first attempt to capture by value fails:

  std::unique_ptr<int> p(new int);
  *p = 11;
  auto y = [p]() { std::cout << "inside: " << *p << "\n";};

This code generates a compiler error because unique_ptr does not generate a copy constructor — it specifically wants to ban making copies.

Changing this so that p is captured by reference compiles fine, but it doesn't have the desired effect of sinking the value by moving the value into the local copy. Eventually, you could accomplish this by creating a local variable and calling std::move() on your captured reference, but this is a bit inefficient.

The fix for this is a modification of the capture clause syntax. Now, instead of just declaring a capture variable, you can do an initialization. The simple case that is used as an example in the standard looks like this:

    auto y = [&r = x, x = x+1]()->int {...}

This captures a copy of x and increments the value simultaneously. The example is easy to understand, but I'm not sure it captures the value of this new syntax for sinking move-only variables. A use case that takes advantage of this shown here:

#include <memory>
#include <iostream>

int main()
{
  std::unique_ptr<int> p(new int);
  int x = 5;
  *p = 11;
  auto y = [p=std::move(p)]() { std::cout << "inside: " << *p << "\n";};
  y();
  std::cout << "outside: " << *p << "\n";
  return 0;
}

In this case, the captured value p is initialized using move semantics, effectively sinking the pointer without the need to declare a local variable:

inside: 11
Segmentation fault (core dumped)

That annoying result is what you expect — the code attempts to dereference p after it was captured and moved into the lambda.

The [[deprecated]] Attribute

The first time I saw the use of the deprecated attribute in Java, I admit to a bit of language envy. Code rot is a huge problem for most programmers. (Ever been praised for deleting code? Me neither.) This new attribute provides a systematic way to attack it.

Its use is convenient and simple — just place the [[deprecated]] tag in front of a declaration — which can be a class, variable, function, or a few other things. The result looks like this:

class
[[deprecated]] flaky {
};

When your program uses a deprecated entity, the compiler's reaction is left up to the implementer. Clearly, most people are going to want to see some sort of warning, and also to be able to turn that warning off at will. As an example, clang 3.4 gave this warning when instantiating a deprecated class:

dep.cpp:14:3: warning: 'flaky' is deprecated [-Wdeprecated-declarations]
  flaky f;
  ^
dep.cpp:3:1: note: 'flaky' declared here
flaky {
^

Note that the syntax of C++ attribute-tokens might seem a bit unfamiliar. The list of attributes, including [[deprecated]], comes after keywords like class or enum, and before the entity name.

This tag has an alternate form that includes a message parameter. Again, it is up to the implementer to decide what to do with this message. clang 3.4 apparently ignores the message. The output from this fragment:

class
[[deprecated]] flaky {
};

[[deprecated("Consider using something other than cranky")]]
int cranky()
{
   return 0;
}

int main()
{
  flaky f;
  return cranky();
}

does not contain the error message:

dep.cpp:14:10: warning: 'cranky' is deprecated [-Wdeprecated-declarations]
  return cranky();
         ^
dep.cpp:6:5: note: 'cranky' declared here
int cranky()
    ^

Binary Literals and Digit Separators

These two new features aren't earth-shaking, but they do represent nice syntactic improvements. Small changes like these give us some incremental improvements in the language that improve readability, and hence, reduce bug counts.

C++ programmers can now create binary literals, adding to the existing canon of decimal, hex, and the rarely used octal radices. Binary literals start with the prefix 0b and are followed by binary digits.

In the U.S. and UK, we are accustomed to using commas as digit separators in written numbers, as in: $1,000,000. These digit separators are there purely for the convenience of readers, providing syntactic cues that make it easier for our brains to process long strings of numbers.

The committee added digit separators to C++ for exactly the same reasons. They won't affect the evaluation of a number, they are simply present to make it easier to read and write numbers through chunking.

What character to use for a digit separator? Virtually every punctuation character already has an idiosyncratic use in the language, so there are no obvious choices. The final election was to use the single quote character, making the million dollar value render in C++ as: 1'000'000.00. Remember that the separators don't have any effect on the evaluation of the constant, so this value would be identical to 1'0'00'0'00.00.

An example combining the use of both new features:

#include <iostream>

int main()
{
  int val = 0b11110000;
  std::cout << "Output mask: "
            << 0b1000'0001'1000'0000
            << "\n";
  std::cout << "Proposed salary: $"
            << 300'000.00
            << "\n";
  return 0;
}

This program gives the unsurprising output:

Output mask: 33152
Proposed salary: $300000

The remainder

Some additional features in the C++14 specification don't require quite as much exposition.

Variable templates are an extension of templates to variables. The example used everywhere is an implementation of variable pi<T>. When implemented as a double, the variable will return 3.14, when implemented as an int, it might return 3, and "3.14" or perhaps "pi" as an std::string. This would have been a great feature to have when <limits> was being written.

The syntax and semantics of variable templates are nearly identical to those for class templates — you should have no trouble using them without any special study.

The restrictions on constexpr functions have been relaxed, allowing, for example, multiple returns, internal case and if statements, loops, and more. This expands the scope of things that are done at compile time, a trend that really took wing when templates were introduced.

Additional minor features include sized deallocations and some syntax tidying.

What Next?

The C++ committee clearly feels pressure to keep the language current through improvements, and it is already working on at least one more standard in this decade, C++17.

Possibly more interesting is the creation of several spin-off groups that can create technical specifications, documents that won't rise to the level of a standard but will be published and endorsed by the ISO committee. Presumably these can be issued at a more rapid clip. The eight areas currently being worked include:

  • File system
  • Concurrency
  • Parallelism
  • Networking
  • Concepts, the AI of C++ — always one round of specification away

Success of these technical specifications will have to be judged by adoption and use. If we find that all the implementers line up behind them, then this new track for standardization will be a success.

C/C++ has held up well over the years. Modern C++, which we might mark as starting with C++11, has taken dramatic strides in making the language easier to use and safer without making concessions in the areas of performance. For certain types of work it is hard to think of any reasonable alternative to C or C++. The C++ 14 standard doesn't make any jumps as large as that in the C++11 release, but it keeps the language on a good path. If the committee can keep its current level of productivity for the rest of the decade, C++ should continue to be the language of choice when performance is the defining goal.


Mark Nelson is a frequent contributor to Dr. Dobb's and lead author of the Data Compression Book.


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.