Articles & Books

Concurrency: From Theory to Practice -- Lucian Radu Teodorescu

concurrencyteodorescu.pngConcurrency is a complicated topic. Lucian Radu Teodorescu provides a simple theory of concurrency which is easy to reason about and apply.

Concurrency: From Theory to Practice

by Lucian Radu Teodorescu

From the article:

One of the big challenges with concurrency is the misalignment between theory and practice. This includes the goals of concurrency (e.g., improving the performance of the application) and the means we use to achieve that goal (e.g., blocking primitives that slow down the program). The theory of concurrency is simple and elegant. In practice, concurrency is often messy and strays from the good practices of enabling local reasoning and using structured programming.

We present a concurrency model that starts from the theory of concurrency, enables local reasoning, and adheres to the ideas of structured programming. We show that the model can be put into practice and that it yields good results.

Most of the ideas presented here are implemented in a C++ library called concore2full [concore2full]. The library is still a work in progress. The original goal for this model and for this library was its inclusion in the Hylo programming language [Hylo]. For Hylo, we want a concurrency model that allows local reasoning and adheres to the structured programming paradigm. We also wanted a model in which there is no function colouring [Nystrom15], in which concurrency doesn’t require a different programming paradigm.

This article is based on a talk I gave at the ACCU 2024 conference [Teodorescu24]. The conference was great! The programme selection was great; there was always something of interest to me. With many passionate C++ engineers and speakers, the exchange of information between participants was excellent; as they say, the best track was the hallway track. I highly encourage all C++ enthusiasts (and not just C++) to participate in future ACCU conferences.

Fat API Bindings of C++ Objects into Scripting Languages -- Russell K. Standish

fatstandish.pngHow do you expose a C++ object to a TypeScript layer or other scripting language? Russell K. Standish demonstrates an approach using a RESTService API that is scripting-language independent.

Fat API Bindings of C++ Objects into Scripting Languages

by Russell K. Standish

From the article:

fat API exposes nearly all of a C++ object’s public attributes and methods to a consuming environment, such as a scripting language, or web client. This can be contrasted with a conventional, or thin API, where the API is defined up front, and the C++ object provides the implementation, most of which is private to the C++ layer.

Obviously, reflection is required to expose C++ objects to a consuming layer like this – this paper explores using the Classdesc system to implement reflection of C++ objects into a JavaScript/TypeScript environment via a REST service, and also via a Node.js API module.

User-Defined Formatting in std::format – Part 2 -- Spencer Collyer

logo.pngLast time, we saw how to provide formatting for a simple user-defined class. Spencer Collyer builds on this, showing how to write a formatter for more complicated types.

User-Defined Formatting in std::format – Part 2

by Spencer Collyer

From the article:

In the previous article in this series [Collyer24], I showed how to write a class to format user-defined classes using the std::format library. In this article I will describe how this can be extended to container classes or any other class that holds objects whose type is specified by the user of your class.

A note on the code listings: The code listings in this article have lines labelled with comments like // 1. Where these lines are referred to in the text of this article, it will be as ‘line 1’ for instance, rather than ‘the line labelled // 1’.

Nested formatter objects

The objects created from the formatter template structs are just ordinary C++ objects – there is nothing special about them 1. In particular, there is nothing to stop you including an object of a formatter template type inside one of your user-defined formatter structs.

You might wonder why you would want to do that. One simple case is if you have a templated container class, and want to create a formatter that can output the container in one go, rather than having to write code to iterate over the container and output each value in turn. Having a nested formatter for the contained value type allows you to do this and allow the values to be formatted differently to the default, as the following examples will show. Other uses will no doubt come to mind for your own classes.

Qt and Trivial Relocation (Part 4) -- Giuseppe D'Angelo

dangeloqt.pngThe conclusion of the last post was that we need to change something in our models: maybe std::vector should use a different strategy when erasing elements; maybe types like std::tuple<int &> should not be allowed to be stored in a vector; maybe Qt should not be using memmove when erasing objects of trivially relocatable type (but it can still optimize the reallocation of a vector); maybe Qt’s definition of trivial relocability does not match ours, and we need to fix our definitions. In this post we will explore these possibilities and reach some conclusions.

Qt and Trivial Relocation (Part 4)

by Giuseppe D'Angelo

From the article:

As we have already discussed in the previous blog posts, it is possible to implement erasure in a number of ways, which are not equivalent. The Standard Library chose a specific implementation strategy (move-assign the elements after the ones to be destroyed to the left; destroy the moved-from last elements). Changing it now, over 26 years after the fact, sounds extremely scary; std::vector is such a central class that surely such a change would break somebody’s code.

That doesn’t mean that we can’t at least reason about a possible change there!

Also, there is another library that we keep talking about in these blog posts. This other library has a much smaller userbase than the Standard Library, and that has fewer regards with breaking backwards compatibility. We should certainly reason about that library as well. I’m talking about Qt, of course ��

Final report from using std::cpp 2024

From April 24th to 26th we had our annual edition of the C++ conference using std::cpp 2024. This is the major conference held in Spain since 2013.

Our final report has now been published:

Report from using std::cpp 2024

It includes answers to many interesting questions from the audience, not only about the conference, but also about the state of the C++ programming language ecosystem.

Do you want to know which is the most widely used version of the C++ language amont our attendees? What are the most popular platforms and compilers? Which tools are used?

And above all, do you really want to know which one was considered the best talk in the conference?

Qt and Trivial Relocation (Part 3) -- Giuseppe D'Angelo

kdab.pngIn the last post of this series we started exploring how to erase an element from the middle of a vector.

Qt and Trivial Relocation (Part 3)

by Giuseppe D'Angelo

From the article:

The reference semantics backstab

Let’s start by analyzing erase()‘s behavior once more.

Do you remember our claim that the specific strategy used does not really matter; that is, that they are all equivalent? Well, not so fast! It is actually quite imprecise to say that they are all equivalent.

They may be, as long as we deal with types which have value semantics. If we instead use a type that has reference semantics, the choices are absolutely not equivalent, and will yield different outcomes. This is because the semantics of assignment for (certain) reference types are write-through: they assign through the reference (instead of rebinding the reference).

Since we are implementing erasure in terms of assignments (or swaps, which boil down to assignments), this means that the precise sequence of operations done by erase will be visible due to its side-effects; and it also means that changing the strategy will produce different outcomes!

C++ programmer's guide to undefined behavior: part 2 of 11

Your attention is invited to the second part of an e-book on undefined behavior. This is not a textbook, as it's intended for those who are already familiar with C++ programming. It's a kind of C++ programmer's guide to undefined behavior and to its most secret and exotic corners. The book was written by Dmitry Sviridkin and edited by Andrey Karpov.

C++ programmer's guide to undefined behavior: part 2 of 11

by Dmitry Sviridkin

From the article:

The compiler can be guided by the following logic: If the h value is positive—regardless of the c character—the h*27752 + c value will be positive: the c value is small, and there is no overflow. At the first iteration, h is positive, we sum up positive numbers. There are no overflows in a correct program, so at each iteration, the value will be positive. The result will be positive; we no need any check.

More on Harmful Overuse of std::move -- Raymond Chen

RaymondChen_5in-150x150.jpgIn recent discussions around the use of std::move in C++, questions have arisen regarding its potential overuse and the compiler's treatment of its return values. Addressing concerns raised by developers like Jonathan Duncan, this article delves into the nuances of std::move, examining whether its current implementation aligns with compiler optimizations and proposing potential enhancements for more efficient code generation.

More on harmful overuse of std::move

by Raymond Chen

From the article:

Some time ago, I wrote about harmful overuse of std::move. Jonathan Duncan asked,

Is there some side-effect or other reason I can’t see return std::move(name); case isn’t possible to elide? Or is this just a case of the standards missing an opportunity and compilers being bound to obey the standards?

In the statement return std::move(name);, what the compiler sees is return f(...); where f(...) is some mysterious function call that returns an rvalue. For all it knows, you could have written return object.optional_name().value();, which is also a mysterious function call that returns an rvalue. There is nothing in the expression std::move(name) that says, “Trust me, this rvalue that I return is an rvalue of a local variable from this very function!”

Now, you might say, “Sure, the compiler doesn’t know that, but what if we made it know that?” Make the function std::move a magic function, one of the special cases where the core language is in cahoots with the standard library.

This sort of in-cahoots-ness is not unheard of. For example, the compiler has special understanding of std::launder, so that it won’t value-propagate memory values across it, and the compiler has special understanding of memory barriers, so that it won’t optimize loads and stores across them.

Qt and Trivial Relocation (Part 2) -- Giuseppe D'Angelo

kdab.pngIn this installment we are going to explore the relationships between trivial relocation and move assignments.

Qt and Trivial Relocation (Part 2)

by Giuseppe D'Angelo

From the article:

Last time we started our investigation of trivial relocation by considering an important use-case: reallocating a vector. This happens when a vector reaches its capacity, but more storage is needed.

Let’s now consider a different operation: erasing an element from the middle of a QVector.

How do we go about it?

isocpp-dangelo.png

Pulling a Single Item From a C++ Parameter Pack by its Index -- Raymond Chen

RaymondChen_5in-150x150.jpgThis article explores techniques to access specific elements within a C++ parameter pack by index. It delves into the use of std::tie for creating a tuple of lvalue references and explains how std::forward_as_tuple can preserve the original reference categories of the parameters. Additionally, it highlights a proposed feature in C++26, Pack Indexing, which aims to simplify this process significantly.

Pulling a Single Item From a C++ Parameter Pack by its Index

by Raymond Chen

From the article:

Suppose you have a C++ parameter pack and you want to pluck out an item from it by index.

template<int index, typename...Args>
void example(Args&&... args)
{
    // how do I access the index'th args parameter?
}

One solution is to use std::tie:

template<int index, typename...Args>
void example(Args&&... args)
{
    auto& arg = std::get<index>(
        std::tie(args...));
}