Reader small image

You're reading from  C++ High Performance

Product typeBook
Published inJan 2018
Reading LevelIntermediate
PublisherPackt
ISBN-139781787120952
Edition1st Edition
Languages
Right arrow
Authors (2):
Björn Andrist
Björn Andrist
author image
Björn Andrist

Björn Andrist is a freelance software consultant currently focusing on audio applications. For more than 15 years, he has been working professionally with C++ in projects ranging from UNIX server applications to real-time audio applications on desktop and mobile. In the past, he has also taught courses in algorithms and data structures, concurrent programming, and programming methodologies. Björn holds a BS in computer engineering and an MS in computer science from KTH Royal Institute of Technology.
Read more about Björn Andrist

Viktor Sehr
Viktor Sehr
author image
Viktor Sehr

Viktor Sehr is the founder and main developer of the small game studio Toppluva AB. At Toppluva he develops a custom graphics engine which powers the open-world skiing game Grand Mountain Adventure. He has 13 years of professional experience using C++, with real-time graphics, audio, and architectural design as his focus areas. Through his career, he has developed medical visualization software at Mentice and Raysearch Laboratories as well as real-time audio applications at Propellerhead Software. Viktor holds an M.S. in media science from Linköping University.
Read more about Viktor Sehr

View More author details
Right arrow

Modern C++ Concepts

In this chapter, we will take an in-depth look at some modern C++ concepts such as move-semantics, forwarding references, std::optional, std::any, and lambda functions. Some of these concepts still confuse even experienced C++ programmers and therefore we will look into both their use cases and how they work under the hood.

Automatic type deduction with the auto keyword

Since the introduction of the auto keyword in C++11, there has been a lot of confusion in the C++ community about how to use the different flavors of auto, such as const auto&, auto&, and auto&&.

Using auto in function signatures

Although discouraged by some C++ programmers, in our experience the use of auto in function signatures vastly increases readability when browsing and viewing header files.

Here is how the new auto syntax looks compared to the old syntax with explicit types:

Old syntax with explicit type: New syntax with auto:
struct Foo {
int val() const {
return m_;
}
const int& cref() const {
return m_;
}
int& mref() {
...

The lambda function

The lambda function, introduced in C++11 and further enhanced with polymorphic capabilities in C++14, is one of the most useful features in modern C++. Its versatility comes not only from easily passing functions to algorithms but it can also be used in a lot of circumstances where you need to pass the code around, especially as you can store a lambda function in std::function.

Although the lambda function made these programming techniques vastly simpler to work with, everything here is possible to perform without them by making classes with operator() overloaded.

We will explore the lambda function's similarities to these kind of classes later, but first let's introduce the lambda function in a simple use case.

Basic syntax of a C++ lambda function

...

Const propagation for pointers

A common mistake when writing const-correct code in C++ is that a const initialized object can still manipulate the values that member pointers points at. The following example illustrates the problem:

class Foo {
public:
Foo(int* ptr) : ptr_{ptr} {}
auto set_ptr_val(int v) const {
*ptr_ = v; // Compiles despite function being declared const!
}
private:
int* ptr_{};
};

auto main() -> int {
const auto foo = Foo{};
foo.set_ptr_val(42);
}

Although the function set_ptr_val() is mutating the int value, it's valid to declared it const since the pointer ptr_ itself is not mutated, only the int object that the pointer is pointing at.

In order to prevent this in a readable way, a wrapper called std::experimental::propagate_const has been added to the std library extensions (included in, as of the time of writing this, the latest versions of...

Move semantics explained

Move semantics is a concept introduced in C++11 which, in our experience, is quite hard to grasp even by experienced programmers. Therefore, we will try to give you an in-depth explanation of how it works, when the compiler utilizes it, and, most importantly, why it is needed.

Essentially, the reason C++ even has the concept of move semantics, whereas most other languages don't, is a result of being a value-based language as discussed in Chapter 1, A Brief Introduction to C++. If C++ did not have move semantics built in, the advantages of value-based semantics would get lost in many cases and programmers would have to perform one of the following trade-offs:

  • Performing redundant deep-cloning operations with high performance costs
  • Using pointers for objects like Java do, losing the robustness of value semantics
  • Performing error-prone swapping operations...

Representing optional values with std::optional

Although quite a minor feature in C++17, std::optional is a neat addition to the STL library which simplifies a common case which couldn't be expressed in a clean straightforward syntax prior to std::optional. In a nutshell, it is a small wrapper for any type where the wrapped type can be both initialized and uninitialized.

To put it in C++ lingo, std::optional is a stack-allocated container with a max size of one.

Note that the Boost Libraries has had an equivalent of std::optional,named boost::optional for many years.

Optional return values

Before the introduction of std::optional, there was no clear way to define functions which may not return a defined value, such as...

Representing dynamic values with std::any

Just like std::optional, std::any can store an optional single value, but with the difference that it can store any type at runtime, just like a dynamically typed}language. As the std::any can withhold any type, you need to explicitly specify the type using the global function std::any_cast when reading the held object.

If the std::any is empty or withholds another type than the specified type, an exception is thrown.

Here is an example of how it works:

// Initialize an empty std::any 
auto a = std::any{};
// Put a string in it
a = std::string{"something"};
// Return a reference to the withheld string
auto& str_ref = std::any_cast<std::string&>(a);
// Copy the withheld string
auto str_copy = std::any_cast<std::string>(a);
// Put a float in the 'any' and read it back
a = 135.246f;
auto flt = std::any_cast...

Summary

In this chapter you have learned how to use modern C++ features such as forwarding references, move-semantics, lambda functions, std::any, and std::optional. In the next chapter we will look into strategies for how to measure performance in C++.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
C++ High Performance
Published in: Jan 2018Publisher: PacktISBN-13: 9781787120952
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Authors (2)

author image
Björn Andrist

Björn Andrist is a freelance software consultant currently focusing on audio applications. For more than 15 years, he has been working professionally with C++ in projects ranging from UNIX server applications to real-time audio applications on desktop and mobile. In the past, he has also taught courses in algorithms and data structures, concurrent programming, and programming methodologies. Björn holds a BS in computer engineering and an MS in computer science from KTH Royal Institute of Technology.
Read more about Björn Andrist

author image
Viktor Sehr

Viktor Sehr is the founder and main developer of the small game studio Toppluva AB. At Toppluva he develops a custom graphics engine which powers the open-world skiing game Grand Mountain Adventure. He has 13 years of professional experience using C++, with real-time graphics, audio, and architectural design as his focus areas. Through his career, he has developed medical visualization software at Mentice and Raysearch Laboratories as well as real-time audio applications at Propellerhead Software. Viktor holds an M.S. in media science from Linköping University.
Read more about Viktor Sehr