Over a million developers have joined DZone.

C++ in Detail: Language Clarifications

DZone's Guide to

C++ in Detail: Language Clarifications

In this article, we continue our up close inspection of C++17 and see what aspects of this language have been made easier for devs to use.

· Web Dev Zone
Free Resource

Add user login and MFA to your next project in minutes. Create a free Okta developer account, drop in one of our SDKs to your application and get back to building.

The second part of my series about C++17 in detail. Today I’d like to focus on features that clarify some tricky parts of the language. For example, copy elision and expression evaluation order.


You all know this… C++ is a very complex language, and some (or most?) parts are quite confusing. One of the reasons for the lack of clarity might be a free choice for the implementation/compiler - for example to allow for more aggressive optimizations or be backward (or C) compatible. Sometimes, it’s simply a lack of time/effort/cooperation. C++17 reviewed some of the most popular ‘holes’ and addressed them. In the end, we got a bit clearer way of how things might work.

Today I’d like to talk about:

  • Evaluation order.
  • Copy elision (an optional optimization that seems to be implemented across all of the popular compilers).
  • Exceptions.
  • Memory allocations for (over)aligned data.

Documents and Links

Just to recall:

First of all, if you want to dig into the standard on your own, you can read the latest draft here: N4659, 2017-03-21, Working Draft, Standard for Programming Language C++ - the link also appears on the isocpp.org.

Compiler support: C++ compiler support

Moreover, I’ve prepared a list of concise descriptions of all of the C++17 language features:

Download a free copy of my C++17 Cheat Sheet!

It’s a one-page reference card, PDF.

There’s also a talk from Bryce Lelbach: C++Now 2017: C++17 Features

Stricter Expression Evaluation Order

This one is tough, so please correct me if I am wrong here, and let me know if you have more examples and better explanations. I’ve tried to confirm some details on Slack/Twitter, and hopefully I am not writing nonsenses here.

Let’s try:

C++ doesn’t specify any evaluation order for function parameters. Period.

For example, that’s why make_unique is not just a syntactic sugar, but actually, it guarantees memory safety.

With make_unique:

foo(make_unique<T>(), otherFunction());

And with explicit new.

foo(unique_ptr<T>(new T), otherFunction());

In the above code, we know that new T is guaranteed to happen before the unique_ptr construction, but that's all. For example, new T might happen first, then otherFunction(), and then the unique_ptrconstructor. 
When otherFunction throws, then new T generates a leak (as the unique pointer is not yet created). When you use make_unique, then it’s not possible to leak, even when the order of execution is random. You can find more of such problems in GotW #56: Exception-Safe Function Calls.

With the accepted proposal the order of evaluation should be ‘practical.’


  • in f(a, b, c) - the order of evaluation of a, b, c is still unspecified, but any parameter is fully evaluated before the next one is started. Especially important for complex expressions.
    • If I’m correct, that fixes a problem with make_unique vs unique_ptr<T>(new T()). As a function argument must be fully evaluated before other arguments are.
  • The chaining of functions already works from left to right, but the order of evaluation of inner expressions might be different. See: C++11 - Does this code from “The C++ Programming Language” 4th edition section 36.3.6 have well-defined behavior? - Stack Overflow. To be correct “The expressions are indeterminately sequenced with respect to each other,” see Sequence Point ambiguity, undefined behavior?.
  • Now, with C++17, the chaining of functions will work as expected when they contain such inner expressions, i.e., they are evaluated from left to right. For example, a(expA).b(expB).c(expC) is evaluated from left to right and expA is evaluated before calling b.
  • When using an operator, an overloading order of evaluation is determined by the order associated with the corresponding built-in operator: 
    • So std::cout << a() << b() << c() is evaluated as a, b, c.

And from the paper:

The following expressions are evaluated in the order a, then b, then c: 
1. a.b 
2. a->b 
3. a->*b 
4. a(b1, b2, b3) 
5. b @= a 
6. a[b] 
7. a << b 
8. a >> b

And the most important part of the spec is probably:

The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter.

StackOverflow: What are the evaluation order guarantees introduced by C++17?

More details in P0145R3 and P0400R0. Not yet supported in Visual Studio 2017, GCC 7.0, or Clang 4.0

Guaranteed Copy Elision

Currently, the standard allows eliding in the cases like:

  • When a temporary object is used to initialize another object (including the object returned by a function, or the exception object created by a throw-expression).
  • When a variable that is about to go out of scope is returned or thrown.
  • When an exception is caught by value.

But it’s up to the compiler/implementation to elide or not. In practice, all the constructors’ definitions are required. Sometimes elision might happen only in release builds (optimized), while Debug builds (without any optimization) won’t elide anything.

With C++17, we’ll get clear rules when elision happens, and thus constructors might be entirely omitted.

Why might it be useful?

  • Allow returning objects that are not movable/copyable. We can now skip copy/move constructors. Useful in factories.
  • Improve code portability, and support ‘return by value’ patterns rather than use ‘output params.’


// based on P0135R0
struct NonMoveable 
  // no copy or move constructor:
  NonMoveable(const NonMoveable&) = delete;
  NonMoveable(NonMoveable&&) = delete;

  std::array<int, 1024> arr;

NonMoveable make() 
  return NonMoveable(42);

// construct the object:
auto largeNonMovableObj = make();

The above code wouldn’t compile under C++14 as it lacks copy and move constructors. But with C++17, the constructors are not required, because the object largeNonMovableObj will be constructed in their place.

Defining rules for copy elision is not easy, but the authors of the proposal suggested new, simplified types of value categories:

  • glvalue - 'A glvalue is an expression whose evaluation computes the location of an object, bit-field, or function.'
  • prvalue - A prvalue is an expression whose evaluation initializes an object, bit-field, or operand of an operator, as specified by the context in which it appears.

In short: prvalues perform initialization, glvalues produce locations.

Unfortunately, in C++17 we’ll get copy elision only for temporary objects, not for Named RVO (so it covers only the first point, not for Named Return Value Optimization). Maybe C++20 will follow and add more rules here?

More details: P0135R0, MSVC 2017: not yet. GCC: 7.0, Clang: 4.0.

The Exception Specifications Part of the Type System

Previously, exception specifications for a function didn’t belong to the type of the function, but now it will be part of it.

We’ll get an error in the following case:

void (*p)();
void (**pp)() noexcept = &p; // error: cannot convert to
                         // pointer to noexcept function

struct S { typedef void (*p)(); operator p(); };
void (*q)() noexcept = S(); // error: cannot convert to 
                            // pointer to noexcept

One of the reasons for adding the feature is the possibility to allow for better optimization. That can happen when you have a guarantee that a function is, for example, noexcept.

Also in C++17, Exception specification is cleaned up, using t’s so-called ‘dynamic exception specifications.’ Effectively, you can only use the noexceptspecifier for declaring that a function might throw something or not.

More details: P0012R1, MSVC 2017: not yet, GCC 7.0, Clang 4.0.

Dynamic Memory Allocation for Over-Aligned Data

When doing SIMD, or when you have some other memory layout requirements, you might need to align objects specifically. For example, in SSE, you need a 16-byte alignment (for AVX 256 you need a 32-byte alignment). So you would define a vector4 like:

class alignas(16) vec4 
    float x, y, z, w;
auto pVectors = new vec4[1000];

Note: the alignas specifier has been available since C++11.

In C++11/14 you have no guarantee of how the memory will be aligned. So, you often have to use some special routines like _aligned_malloc/_aligned_free to be sure that the alignment is preserved. That’s not nice, as it’s not working with C++ smart pointers and also make memory allocations/deletions visible in the code (we should stop using raw new and delete, according to Core Guidelines).

C++17 fixes that hole by introducing additional memory allocation functions that use the align parameter:

void* operator new(size_t, align_val_t);
void* operator new[](size_t, align_val_t);
void operator delete(void*, align_val_t);
void operator delete[](void*, align_val_t);
void operator delete(void*, size_t, align_val_t);
void operator delete[](void*, size_t, align_val_t);

Now, you can allocate that vec4 array as:

auto pVectors = new vec4[1000];

No code changes, but it will magically call:

operator new[](sizeof(vec4), align_val_t(alignof(vec4)))

In other words, new is now aware of the alignment of the object.

More details in P0035R4. MSVC 2017: not yet, GCC: 7.0, Clang: 4.0.


Today, we’ve focused on four areas where C++ specification is now clearer. We now have ways to assume Copy Ellison will happen, some orders of operations are well defined now, the operator new is now aware of the alignment of a type, and exceptions are also part of the function declaration.

What are your picks for language clarification?

What are other ‘holes’ needed to be filled?

Next time, we’ll address changes for templates and generic programming. So stay tuned!

Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!

c++ ,web dev ,C++17

Published at DZone with permission of Bartłomiej Filipek, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}