Raw Loops for Performance? -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGUsing ranges or algorithms has several advantages over raw loops, notably readability. On the other hand, as we’ve just seen, sheer performance is not necessarily among those advantages. Using ranges can be slightly slower than a raw loop version. But that’s not necessarily a problem, it really depends on your use case. Most probably it won’t make a bit difference.

Raw Loops for Performance?

by Sandor Dargo

From the article:

To my greatest satisfaction, I’ve recently joined a new project. I started to read through the codebase before joining and at that stage, whenever I saw a possibility for a minor improvement, I raised a tiny pull request. One of my pet peeves is rooted in Sean Parent’s 2013 talk at GoingNative, Seasoning C++ where he advocated for no raw loops.

When I saw this loop, I started to think about how to replace it:

2025-05-08_16-46-14.png

Please note that the example is simplified and slightly changed so that it compiles on its own.

Let’s focus on foo, the rest is there just to make the example compilable.

It seems that we could use std::transform. But heck, we use C++20 we have ranges at our hands so let’s go with std::ranges::transform!

CppCon 2024 When Nanoseconds Matter: Ultrafast Trading Systems in C++ -- David Gross

nanosecondsmatter-gross.pngRegistration is now open for CppCon 2025! The conference starts on September 13 and will be held in person in Aurora, CO. To whet your appetite for this year’s conference, we’re posting videos of some of the top-rated talks from last year's conference. Here’s another CppCon talk video we hope you will enjoy – and why not register today for CppCon 2025!

When Nanoseconds Matter: Ultrafast Trading Systems in C++

by David Gross

Summary of the talk:

Achieving low latency in a trading system cannot be an afterthought; it must be an integral part of the design from the very beginning. While low latency programming is sometimes seen under the umbrella of "code optimization", the truth is that most of the work needed to achieve such latency is done upfront, at the design phase. How to translate our knowledge about the CPU and hardware into C++? How to use multiple CPU cores, handle concurrency issues and cost, and stay fast?

In this talk, I will be sharing with you some industry insights on how to design from scratch a low latency trading system. I will be presenting building blocks that application developers can directly re-use when in their trading systems (or some other high performance, highly concurrent applications).

Additionally, we will delve into several algorithms and data structures commonly used in trading systems, and discuss how to optimize them using the latest features available in C++. This session aims to equip you with practical knowledge and techniques to enhance the performance of your systems and make informed decisions about the tools and technologies you choose to employ.

constexpr Functions: Optimization vs Guarantee -- Andreas Fertig

Depositphotos_193487484_S.jpgConstexpr has been around for a while now, but many don’t fully understand its subtleties. Andreas Fertig explores its use and when a constexpr expression might not be evaluated at compile time.

constexpr Functions: Optimization vs Guarantee

by Andreas Fertig

From the article:

The feature of constant evaluation is nothing new in 2023. You have constexpr available since C++11. Yet, in many of my classes, I see that people still struggle with constexpr functions. Let me shed some light on them.

What you get is not what you see

One thing, which is a feature, is that constexpr functions can be evaluated at compile-time, but they can run at run-time as well. That evaluation at compile-time requires all values known at compile-time is reasonable. But I often see that the assumption is once all values for a constexpr function are known at compile-time, the function will be evaluated at compile-time.

I can say that I find this assumption reasonable, and discovering the truth isn’t easy. Let’s consider an example (Listing 1).

constexpr auto Fun(int v)
{
  return 42 / v; ①
}

int main()
{
  const auto f = Fun(6); ②
  return f;              ③
}
Listing 1

The constexpr function Fun divides 42 by a value provided by the parameter v ①. In ②, I call Fun with the value 6 and assign the result to the variable f.

Last, in ③, I return the value of f to prevent the compiler optimizes this program away. If you use Compiler Explorer to look at the resulting assembly, GCC with -O1 brings this down to:

  main:
          mov     eax, 7
          ret

As you can see, the compiler has evaluated the result of 42 / 6, which, of course, is 7. Aside from the final number, there is also no trace at all of the function Fun.

Now, this is what, in my experience, makes people believe that Fun was evaluated at compile-time thanks to constexpr. Yet this view is incorrect. You are looking at compiler optimization, something different from constexpr functions.

Results summary: 2025 Annual C++ Developer Survey "Lite"

Thank you to everyone who reponded to our 2025 annual global C++ developer survey. As promised, here is a summary of the results, including one-page AI-generated summaries of your answers to the free-form questions:

CppDevSurvey-2025-summary.pdf

A 100-page version of this report that also includes all individual write-in responses has now been forwarded to the C++ standards committee and C++ product vendors, to help inform C++ evolution and tooling.

Your feedback is valuable, and appreciated.

C++26: Erroneous Behaviour -- Sandor Dargo

Depositphotos_287607756_S.jpgC++’s undefined behaviour impacts safety. Sandor Dargo explains how and why uninitialised reads will become erroneous behaviour in C++26, rather than being undefined behaviour.

C++26: Erroneous Behaviour

by Sandor Dargo

From the article:

If you pick a random talk at a C++ conference these days, there is a fair chance that the speaker will mention safety at least a couple of times. It’s probably fine like that. The committee and the community must think about improving both the safety situation and the reputation of C++.

If you follow what’s going on in this space, you are probably aware that people have different perspectives on safety. I think almost everybody finds it important, but they would solve the problem in their own way.

A big source of issues is certain manifestations of undefined behaviour. It affects both the safety and the stability of software. I remember that a few years ago when I was working on some services which had to support a 10× growth, one of the important points was to eliminate undefined behaviour as much as possible. One main point for us was to remove uninitialized variables which often lead to crashing services.

Thanks to P2795R5 by Thomas Köppe, uninitialized reads won’t be undefined behaviour anymore – starting from C++26. Instead, they will get a new behaviour called ‘erroneous behaviour’.

The great advantage of erroneous behaviour is that it will work just by recompiling existing code. It will diagnose where you forgot to initialize variables. You don’t have to systematically go through your code and let’s say declare everything as auto to make sure that every variable has an initialized value. Which you probably wouldn’t do anyway.

But what is this new behaviour that on C++ Reference is even listed on the page of undefined behaviour? [CppRef-1] It’s well-defined, yet incorrect behaviour that compilers are recommended to diagnose. Is recommended enough?! Well, with the growing focus on safety, you can rest assured that an implementation that wouldn’t diagnose erroneous behaviour would be soon out of the game.

Some compilers can already identify uninitialized reads – what nowadays falls under undefined behaviour. For example, clang and gcc with -ftrivial-auto-var-init=zero have already offered default initialization of variables with automatic storage duration. This means that the technique to identify these variables is already there. The only thing that makes this approach not practical is that you will not know which variables you failed to initialize.

Instead of default initialization, with erroneous behaviour, an uninitialized object will be initialized to an implementation-specific value. Reading such a value is a conceptual error that is recommended and encouraged to be diagnosed by the compiler. That might happen through warnings, run-time errors, etc.

Writing Senders -- Lucian Radu Teodorescu

2025-05-08_16-35-43.pngIn the December issue of Overload [Teodorescu24], we provided a gentle introduction to senders/receivers, arguing that it is easy to write programs with senders/receivers. Then, in the February issue [Teodorescu25a], we had an article that walked the reader through some examples showing how senders/receivers can be used to introduce concurrency in an application. Both of these articles focused on the end users of senders/receivers. This article focuses on the implementer’s side: what does it take to implement senders?

Writing Senders

by Lucian Radu Teodorescu

From the article:

If people are just using frameworks based on std::execution, they mainly need to care about senders and schedulers. These are user-facing concepts. However, if people want to implement sender-ready abstractions, they also need to consider receivers and operation states – these are implementer-side concepts. As this article mainly focuses on the implementation of sender abstractions, we need to discuss these two concepts in more detail.

A receiver is defined in P2300 as “a callback that supports more than one channel” [P2300R10]. The proposal defines a concept for a receiver, unsurprisingly called receiver. To model this concept, a type needs to meet the following conditions:

  • It must be movable and copyable.
  • It must have an inner type alias named receiver_concept that is equal to receiver_t (or a derived type).
  • std::execution::get_env() must be callable on an object of this type (to retrieve the environment of the receiver).

A receiver is the object that receives the sender’s completion signal, i.e., one of set_value()set_error(), or set_stopped(). As explained in the December 2024 issue [Teodorescu24], a sender may have different value completion types and different error completion types. For example, the same sender might sometimes complete with set_value(int, int), sometimes with set_value(double), sometimes with set_error(std::exception_ptr), sometimes with set_error(std::error_code), and sometimes with set_stopped(). This implies that a receiver must also be able to accept multiple types of completion signals.

The need for completion signatures is not directly visible in the receiver concept. There is another concept that the P2300 proposal defines, which includes the completion signatures for a receiver: receiver_of<Completions>. A type models this concept if it also models the receiver concept and provides functions to handle the completions indicated by Completions. More details on how these completions look will be covered in the example sections.

Learn about generic programming and concepts, views & ranges with Nicolai Josuttis

Meeting C++ is hosting two trainings on the 26th and 27th May with Nicolai Josuttis:

May 26th: Generic programming in C++ with templates and auto

Generic code is key for the success of C++. Almost all parts of the C++ standard library are implemented as templates and with auto. However, the uncertainty when seeing this code and when writing own code is high.

This online training will guide you through the most important elements of generic programming for ordinary application programmers. Based on the general approach for function templates and class templates we cover the more tricky topics like non-type template parameters, variadic templates and fold expressions, class template argument deduction, type traits, and SFINAE.

This can be used as perfect base for the training about C++20/C++23 concepts, which are covered in a training the day after.

 

May 27th: Concepts, Ranges, and Views - The New Way of Programming in C++

Concepts, ranges, and views, introduced with C++20 and extended with C++23, introduce a new way of programming with C++:


    Concepts establish a way to deal with requirements and constraints to simplify overloading and improve error messages of generic code. This sounds simple but changes the way we write code significantly.

    Ranges and views establish a new way to deal with collections and containers. Instead of using begin() and end(), we deal with the collections as a whole. This establishes new ways of data processing (such as defining pipelines) but also introduces new pitfalls and caveats.


Both features were designed together so that they benefit from each other:


    Ranges and views are implemented using concepts to behave well and help with their usage.

    As a consequence, standard concepts were designed according to a real non-trivial application of using them.


This full day tutorial guides you though these new features. The features are motivated and explained so that you understand purpose and design as well as how to use them in practice. This also implies to talk about the most important pitfalls (there are several) so that you avoid wasting time or getting even frustrated by unexpected behavior or strange errors.

 

You also can get both as two in one package.

Using Token Sequences to Iterate Ranges -- Barry Revzin

There was a StackOverflow question recently that led me to want to write a new post about Ranges. Specifically, I wanted to write about some situations in which Ranges do more work than it seems like they should have to. And then what we can do to avoid doing that extra work.

Using Token Sequences to Iterate Ranges

by Barry Revzin

From the article:

The Problem

For the purposes of this post, I’m just going to talk about the very simple problem of:

for (auto elem : r) { 
use(elem); 
} 

In the C++ iterator model, this desugars into something like:

auto __it = r.begin(); 
auto __end = r.end(); 

while (__it != __end) { 
use(*__it); 

++__it; 
} 

I used a while loop here deliberately, because it’s a simpler construct and it lets me write the advance step last.

Now, if you want to customize the behavior of a range, those are your entry points right there. You can change what the initialization phase does (begin() and end()), you can change the check against completeness (__it != __end), you can change the read operation (*__it), and you can change the advance operation (++__it). That’s it. You can’t change the structure of the loop itself.

That alone is enough to offer a pretty large wealth of functionality. It’s a very powerful abstraction.

1-day workshop on May 30: Safe and Efficient C++ for Embedded Environments -- Andreas Fertig

me.pngFriday, May 30th, 2025, 10:00 - 18:00 Berlin time (online)

1-day workshop on May 30: Safe and Efficient C++ for Embedded Environments

by Andeas Fertig

About the training

I'm thrilled to let you know that I'll give the workshop "Safe and Efficient C++ for Embedded Environments".

The workshop will take place on Friday, May 30th, 2025, 10:00 - 18:00 Berlin time. It is a remote workshop, so we can join from everywhere.

The course is specifically for people in the embedded domain. You'll learn about various features of modern C++, as you can see in the outline below:

  • Language features in C++
    • References
    • nullptr
    • Explicit data type conversion
    • Uniform initialization
    • Digit separator
    • auto type deduction
    • range-based for loops
    • Strongly typed enum
    • static or inline
    • Attributes
  • ROM-ability
  • Living without the heap
  • Dynamic memory management
  • alignas & alignof
  • Placement-new
  • Implementing a pool allocator
  • std::launder
  • std::unique_ptr
  • std::start_life_time_as

C++ on Sea 2025 Full Schedule, including workshops

C++ on Sea 2025 runs from 23rd-25th June, with workshops on 26th-27th.

The full 2025 schedule is now available

by C++ on Sea

From the article:

This year we are, once again, running 2-day workshops - but they will be after the main conference, at the end of the week. As usual we have a great range of timely topics from world-class instructors to help you keep ahead.

We'll kick off with [a keynote from] Herb Sutter... regroup in the middle with Timur Doumler... then round out with Kristen Shaker.

Lightning talks... conference dinner... and a C++ quiz night.