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.

2025-05 Mailing Available

The 2025-05 mailing of new standards papers is now available.

 

WG21 Number Title Author Document Date Mailing Date Previous Version Subgroup
N5010 WG21 agenda: 16-21 June 2025, Sofia Bulgaria John Spicer 2025-05-04 2025-05   All of WG21
P0085R1 Oo... adding a coherent character sequence to begin octal-literals Axel Naumann 2025-05-19 2025-05 P0085R0 EWG Evolution,LEWG Library Evolution
P0149R2 Generalised member pointers Jeff Snyder 2025-05-19 2025-05 P0149R1 CWG Core
P0149R3 Generalised member pointers Jeff Snyder 2025-05-19 2025-05 P0149R2 CWG Core
P1144R13 std::is_trivially_relocatable Arthur O'Dwyer 2025-05-14 2025-05 P1144R12 EWG Evolution
P1306R4 Expansion statements Dan Katz 2025-05-17 2025-05 P1306R3 CWG Core
P2079R8 Parallel Scheduler Lucian Radu Teodorescu 2025-05-18 2025-05 P2079R7 LWG Library
P2287R5 Designated-initializers for base classes Barry Revzin 2025-05-17 2025-05 P2287R4 EWG Evolution
P2414R7 Pointer lifetime-end zap proposed solutions Paul E. McKenney 2025-05-14 2025-05 P2414R6 SG1 Concurrency and Parallelism,LEWG Library Evolution,LWG Library
P2434R4 Nondeterministic pointer provenance S. Davis Herring 2025-05-09 2025-05 P2434R3 SG1 Concurrency and Parallelism,SG22 Compatibility,EWG Evolution,CWG Core,LWG Library
P2509R1 A proposal for a type trait to detect value-preserving conversions Giuseppe D'Angelo 2025-05-19 2025-05 P2509R0 SG6 Numerics,LEWG Library Evolution
P2664R10 Proposal to extend std::simd with permutation API Daniel Towner 2025-05-19 2025-05 P2664R9 LWG Library
P2719R5 Type-aware allocation and deallocation functions Louis Dionne 2025-05-12 2025-05 P2719R4 CWG Core
P2902R2 constexpr 'Parallel' Algorithms Oliver Rosten 2025-05-12 2025-05 P2902R1 LEWG Library Evolution,LWG Library
P2927R3 Observing exceptions stored in exception_ptr Gor Nishanov 2025-05-18 2025-05 P2927R2 LWG Library
P2956R1 Add saturating library support to std::simd Daniel Towner 2025-05-19 2025-05 P2956R0 LWG Library
P2970R0 Partial application of concepts in template arguments Corentin Jabot 2025-05-19 2025-05   EWG Evolution
P2996R12 Reflection for C++26 Barry Revzin 2025-05-17 2025-05 P2996R11 EWG Evolution
P3008R5 Atomic floating-point min/max Gonzalo Brito Gadeschi 2025-04-29 2025-05 P3008R4 LWG Library
P3008R5 Atomic floating-point min/max Gonzalo Brito Gadeschi 2025-05-18 2025-05 P3008R4 LWG Library
P3037R6 constexpr std::shared_ptr and friends Paul Keir 2025-05-03 2025-05 P3037R5 LWG Library
P3086R4 Proxy: A Pointer-Semantics-Based Polymorphism Library Mingxin Wang 2025-05-19 2025-05 P3086R3 LEWGI SG18: LEWG Incubator,LEWG Library Evolution
P3096R9 Function Parameter Reflection in Reflection for C++26 Adam Lach 2025-05-15 2025-05 P3096R8 CWG Core,LWG Library
P3100R2 Implicit contract assertions Timur Doumler 2025-05-19 2025-05 P3100R1 EWG Evolution
P3111R6 Atomic Reduction Operations Gonzalo Brito Gadeschi 2025-05-18 2025-05 P3111R5 CWG Core,LWG Library
P3125R4 constexpr pointer tagging Hana Dusíková 2025-05-19 2025-05 P3125R3 LEWG Library Evolution
P3149R10 async_scope -- Creating scopes for non-sequential concurrency Ian Petersen 2025-05-19 2025-05 P3149R9 LWG Library
P3164R4 Early Diagnostics for Sender Expressions Eric Niebler 2025-04-27 2025-05 P3164R3 LWG Library
P3179R8 C++ parallel range algorithms Ruslan Arutyunyan 2025-05-18 2025-05 P3179R7 LWG Library
P3284R4 `write_env` and `unstoppable` Sender Adaptors Eric Niebler 2025-05-16 2025-05 P3284R3 LWG Library
P3293R2 Splicing a base class subobject Barry Revzin 2025-05-11 2025-05 P3293R1 EWG Evolution
P3310R6 Solving issues introduced by relaxed template template parameter matching Matheus Izvekov 2025-05-18 2025-05 P3310R5 EWG Evolution,CWG Core
P3347R2 Invalid/Prospective Pointer Operations Paul E. McKenney 2025-05-14 2025-05 P3347R1 EWG Evolution
P3375R3 Reproducible floating-point results Guy Davidson 2025-05-18 2025-05 P3375R2 SG6 Numerics,SG14 Low Latency,LEWG Library Evolution
P3385R5 Attributes reflection Aurelien Cassagnes 2025-05-19 2025-05 P3385R4 EWG Evolution,LEWG Library Evolution
P3394R3 Annotations for Reflection Daveed Vandevoorde 2025-05-17 2025-05 P3394R2 CWG Core,LWG Library
P3395R4 Fix encoding issues and add a formatter for std::error_code Victor Zverovich 2025-04-27 2025-05 P3395R3 LEWG Library Evolution
P3402R3 A Safety Profile Verifying Initialization Marc-André Laverdière 2025-05-16 2025-05 P3402R2 SG23 Safety and Security,EWG Evolution
P3411R2 `any_view` Hui Xie 2025-05-17 2025-05 P3411R1 SG9 Ranges,LEWG Library Evolution
P3412R2 String interpolation Bengt Gustafsson 2025-05-18 2025-05 P3412R1 EWG Evolution
P3439R2 Chained comparisons: Safe, correct, efficient Herb Sutter 2025-05-10 2025-05 P3439R1 EWG Evolution
P3442R2 [[invalidate_dereferencing]] attribute Patrice Roy 2025-05-19 2025-05 P3442R1 EWG Evolution
P3480R5 std::simd is a range Matthias Kretz 2025-05-15 2025-05 P3480R4 LWG Library
P3516R2 Uninitialized algorithms for relocation Louis Dionne 2025-05-16 2025-05 P3516R1 LWG Library
P3552R2 Add a Coroutine Task Type Dietmar Kühl 2025-05-18 2025-05 P3552R1 LWG Library
P3556R1 Input files are source files Alisdair Meredith 2025-05-19 2025-05 P3556R0 SG16 Unicode,CWG Core
P3557R2 High-Quality Sender Diagnostics with Constexpr Exceptions Eric Niebler 2025-05-16 2025-05 P3557R1 LWG Library
P3560R1 Error Handling in Reflection Barry Revzin 2025-05-19 2025-05 P3560R0 EWG Evolution,LEWG Library Evolution
P3565R1 Virtual floating-point values S. Davis Herring 2025-05-19 2025-05 P3565R0 SG6 Numerics
P3566R1 You shall not pass `char*` - Safety concerns working with unbounded null-terminated strings Marco Foco 2025-05-19 2025-05 P3566R0 SG23 Safety and Security,LEWG Library Evolution,LWG Library,ARG ABI Review Group
P3570R1 optional variants in sender/receiver Fabio Fracassi 2025-05-19 2025-05 P3570R0 LEWG Library Evolution
P3588R1 Allow static data members in local and unnamed classes Brian Bi 2025-05-17 2025-05 P3588R0 EWG Evolution
P3589R2 C++ Profiles: The Framework Gabriel Dos Reis 2025-05-19 2025-05 P3589R1 EWG Evolution
P3617R0 std::meta::reflect_constant_{array,string} Barry Revzin 2025-05-16 2025-05   LEWG Library Evolution
P3631R0 Cleaning up the trivial relocation APIs in C++26 Louis Dionne 2025-05-18 2025-05   LEWG Library Evolution,LWG Library
P3649R0 A principled approach to safety profiles Jonathan Müller 2025-05-19 2025-05   SG23 Safety and Security
P3655R1 zstring_view Peter Bindels 2025-05-19 2025-05 P3655R0 LEWG Library Evolution
P3658R1 Adjust identifier following new Unicode recommendations Robin Leroy 2025-05-15 2025-05 P3658R0 EWG Evolution
P3663R1 Future-proof `submdspan-mapping` Mark Hoemmen 2025-05-16 2025-05 P3663R0 LWG Library
P3668R1 Defaulting Postfix Increment and Decrement Operations Matthew Taylor 2025-05-16 2025-05 P3668R0 EWGI SG17: EWG Incubator
P3669R1 Non-Blocking Support for `std::execution` Detlef Vollmann 2025-05-17 2025-05 P3669R0 SG1 Concurrency and Parallelism,LEWG Library Evolution
P3670R1 Pack Indexing for Template Names Corentin Jabot 2025-05-03 2025-05 P3670R0 EWG Evolution
P3676R0 Enhanced inline Keyword with Configurable Inlining Levels Stephen Berry 2025-04-17 2025-05   SG14 Low Latency,EWGI SG17: EWG Incubator,LEWGI SG18: LEWG Incubator,EWG Evolution,LEWG Library Evolution,CWG Core,LWG Library
P3677R0 Preserving LC_CTYPE at program start for UTF-8 locales Corentin Jabot 2025-05-03 2025-05   SG16 Unicode,SG22 Compatibility
P3678R0 Arbitrary attributes in define_aggregate Aurelien Cassagnes 2025-05-14 2025-05   SG7 Reflection
P3679R0 SFINAEable constexpr exceptions Hana Dusíková 2025-05-16 2025-05   EWG Evolution
P3681R0 char_traits: Stop the bleeding Corentin Jabot 2025-05-19 2025-05   SG16 Unicode
P3682R0 Remove std::execution::split Robert Leahy 2025-05-06 2025-05   LEWG Library Evolution
P3685R0 Rename async_scope_token Robert Leahy 2025-05-07 2025-05   LEWG Library Evolution
P3686R0 Allow named modules to export macros Chuanqi Xu 2025-05-07 2025-05   EWG Evolution
P3687R0 Final Adjustments to C++26 Reflection Dan Katz 2025-05-15 2025-05   EWG Evolution,LEWG Library Evolution,CWG Core,LWG Library
P3688R0 ASCII character utilities Jan Schultke 2025-05-19 2025-05   SG16 Unicode,LEWG Library Evolution
P3689R0 Convenience functions for Random number generation Thomas Mejstrik 2025-05-11 2025-05   LEWGI SG18: LEWG Incubator
P3690R0 Consistency fix: Make simd reductions SIMD-generic Olaf Krzikalla 2025-05-13 2025-05   LEWG Library Evolution
P3691R0 Reconsider naming of the namespace for "std::simd" Matthias Kretz 2025-05-19 2025-05   LEWG Library Evolution
P3692R0 How to Avoid OOTA Without Really Trying Paul E. McKenney 2025-05-13 2025-05   SG1 Concurrency and Parallelism
P3693R0 SG14: Low Latency/Games/Embedded/Financial Trading virtual Meeting Minutes 2025/04/09-2025/05/07 Michael Wong 2025-05-15 2025-05   SG14 Low Latency
P3694R0 SG19: Machine Learning virtual Meeting Minutes to 2025/03/13-2025/05/08 Michael Wong 2025-05-15 2025-05   SG19 Machine Learning
P3695R0 Deprecate implicit conversions between Unicode character types Jan Schultke 2025-05-17 2025-05   SG16 Unicode,EWG Evolution
P3696R0 Discovering Header Units via Module Maps Michael Spencer 2025-05-19 2025-05   SG15 Tooling
P3697R0 Minor additions to C++26 standard library hardening Konstantin Varlamov 2025-05-15 2025-05   LEWG Library Evolution,LWG Library
P3698R0 Cross-capacity comparisons for inplace_vector Charles Hussong 2025-05-19 2025-05   LEWG Library Evolution
P3699R0 Rename `conqueue_errc` Detlef Vollmann 2025-05-17 2025-05   LEWG Library Evolution
P3700R0 Making Safe C++ happen Peter Bindels 2025-05-19 2025-05   SG21 Contracts,SG23 Safety and Security,EWG Evolution
P3701R0 Concepts for integer types, not integral types Jan Schultke 2025-05-19 2025-05   LEWG Library Evolution
P3702R0 Stricter requirements for document submissions (SD-7) Jan Schultke 2025-05-19 2025-05   All of WG21
P3703R0 Constness and Locking Yoaodan Zhang 2025-05-18 2025-05   SG1 Concurrency and Parallelism
P3704R0 What are profiles? Bjarne Stroustrup 2025-05-19 2025-05   SG20 Education,SG23 Safety and Security,EWG Evolution,LEWG Library Evolution
P3705R0 A Sentinel for Null-Terminated Strings Eddie Nolan 2025-05-19 2025-05   SG9 Ranges,LEWG Library Evolution
P3706R0 Rename join and nest in async_scope proposal Ruslan Arutyunyan 2025-05-19 2025-05   LEWG Library Evolution
P3707R0 A std::is_always_exhaustive trait Patrice Roy 2025-05-19 2025-05   SG14 Low Latency,LEWG Library Evolution
P3709R0 Reconsider parallel ranges::rotate_copy and ranges::reverse_copy Ruslan Arutyunyan 2025-05-18 2025-05   LEWG Library Evolution
P3710R0 zstring_view: a string_view with guaranteed null termination Alexey Shevlyakov, Marco Foco 2025-05-19 2025-05   SG23 Safety and Security,LEWG Library Evolution
P3711R0 Safer StringViewLike Functions for Replacing char* strings Marco Foco 2025-05-19 2025-05   SG23 Safety and Security,LEWG Library Evolution
P3712R0 2025-05 Library Evolution Polls Inbal Levi 2025-05-19 2025-05   All of WG21
P3714R0 Virtual values have Virtual Value Joshua Cranmer 2025-05-19 2025-05   SG6 Numerics
P3715R0 Tightening floating-point semantics for C++ Joshua Cranmer 2025-05-19 2025-05   SG6 Numerics,SG22 Compatibility
P3716R0 Subsetting Peter Bindels 2025-05-19 2025-05   SG23 Safety and Security,EWG Evolution
P3717R0 Update Annex E onto Unicode 16 Steve Downey 2025-05-19 2025-05   SG16 Unicode,EWG Evolution,CWG Core

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.

 

free performance: autobatching in my SFML fork -- Vittorio Romeo

This article shows how a very simple automatic batching strategy can be applied on top of SFML without affecting the library API, resulting in free performance for the end user!

free performance: autobatching in my SFML fork

by Vittorio Romeo

From the article:

In one of my previous articles, I discussed the design and implementation of the batching system in my fork of SFML. Wouldn’t it be nice if drawables were automatically batched, whenever possible?

AoS vs SoA in practice: particle simulation -- Vittorio Romeo

This article presents a practical benchmark of a particle simulation using both the AoS (Array of Structures) and SoA (Structure of Arrays) data layouts. How much performance can we gain by merely switching up the way our data is stored?

AoS vs SoA in practice: particle simulation

by Vittorio Romeo

From the article:

The benchmark simulates a large number of 2D particles that continuously change position, scale, opacity, and rotation. Through an ImGui-based UI1, you can choose the number of particles, toggle multithreading, and switch between AoS and SoA on the fly.

A demo is worth a thousand words, and since my fork of SFML supports Emscripten, you can try the benchmark directly in your browser. Play around with all the options – I’m curious to hear what results you get! [...]

CLion Is Now Free for Non-Commercial Use

Great news for C++ enthusiasts working on personal projects! JetBrains has announced that CLion is now available for free for non-commercial use.

CLion Is Now Free for Non-Commercial Use

by JetBrains

From the article:

"Whether you're a student, an Arduino experimenter, or someone who loves С and C++ with all your heart despite all the challenges these languages present, CLion is now available to you for free – as long as you're not using it for commercial work."