Articles & Books

Solving Undefined Behavior in Factories with constinit from C++20 -- Bartlomiej Filipek

ub_constinit.pngA few years ago, I showed an interesting implementation for self-registering classes in factories. It works, but one step might be at the edge of Undefined behavior. Fortunately, with C++20, its new constinit keyword, we can update the code and ensure it’s super safe.

Solving Undefined Behavior in Factories with constinit from C++20

by Bartlomiej Filipek

From the article:

Let’s bring back the topic:

Here’s a typical factory function. It creates unique_ptr with ZipCompression or BZCompression based on the passed name/filename:

Here are some issues with this approach:

  • Each time you write a new class, and you want to include it in the factory, you have to add another if in the Create() method. Easy to forget in a complex system.
  • All the types must be known to the factory.
  • In Create(), we arbitrarily used strings to represent types. Such representation is only visible in that single method. What if you’d like to use it somewhere else? Strings might be easily misspelled, especially if you have several places where they are compared.

All in all, we get a strong dependency between the factory and the classes.

But what if classes could register themselves? Would that help?

The Move Constructor That You Have to Declare, Even Though You Don’t ... -- Raymond Chen

RaymondChen_5in-150x150.jpgYou may have a class that you want to participate in RVO or NRVO, but you also don’t want it to be moved. For example, it may contain a std::mutex, which is not movable. But you nevertheless have to declare a move constructor. What can you do?

The Move Constructor That You Have to Declare, Even Though You Don’t Want Anyone to Actually Call It

by Raymond Chen

From the article:

Blah blah blah C++ return value optimization (RVO), named return value optimization (NRVO), and copy elision.

RVO support was optional in C++11 but became mandatory in C++17. NRVO support remains optional (but recommended).

To allow NRVO in C++17 (or RVO and NRVO in C++11), a move constructor must be available, even though the compiler will not call it if the optimization is employed.

You may have a class that you want to participate in RVO or NRVO, but you also don’t want it to be moved. For example, it may contain a std::mutex, which is not movable. But you nevertheless have to declare a move constructor. What can you do?

Declare the move constructor, but...

Need Something Sorted? Sleep On It! -- Kevlin Henney

kevlinhenney.jpgSorting algorithms have been thoroughly studied. Kevlin Henney takes an unexpected paradigm journey into sleep sort.

Need Something Sorted? Sleep On It!

by Kevlin Henney

From the article:

A decade ago, I first presented a lightning talk entitled ‘Cool Code’. This short talk evolved into a full talk whose iterations I presented over the next half decade. The focus? Code that, for some reason or other, can be considered cool. For example, code that has played a significant role in historical events, such as the source for the Apollo Guidance Computer [Apollo]. Or code that is audacious – if not seemingly impossible – given its constraints, such as David Horne’s 1K chess [Frogley01]. There is code that is both simple and profound, such as Peter Norvig’s fits-on-a-slide spelling corrector [Norvig16]. And code that demonstrates ingenuity and humour, such as Yusuke Endoh’s Qlobe [Endoh10].

Leaving aside its content for a moment, one of the most interesting things about the talk was its...

Why You Should Only Rarely Use std::move -- Andreas Fertig

andreas-fertig.pngstd::move can allow the efficient transfer of resources from object to to object. Andreas Fertig reminds us that using std::move inappropriately can make code less efficient.

Why You Should Only Rarely Use std::move

by Andreas Fertig

From the article:

The example in Listing 1 is the code I used to make my point: don’t use std::move on temporaries! Plus, in general, trust the compiler and only use std::move rarely. For this article, let’s focus on the example code.

class S {
public:
  S() { printf("default constructor\n"); }
  ~S() { printf("deconstructor\n"); }
  // Copy constructor ①
  S(const S&) { printf("copy constructor\n"); }
  // Move constructor ②
  S(S&&) { printf("move constructor\n"); }
};
void Use()
{
  S obj{
    S{} // Creating obj with a temporary of S ③
  };
}
Listing 1

Here we see a, well, perfectly movable class. I left the assignment operations out. They are not relevant. Aside from the constructor and destructor, we see in ① the copy constructor and in ② the move constructor. All special members print a message to identify them when they are called.

Further down in Use, we see ③, a temporary object of S used to initialize obj, also of type S. This is the typical situation where move semantics excels over a copy (assuming the class in question has movable members). The output I expect, and I wanted to show my participants, is:

Type Safe C++ enum Extensions -- Alf Steinbach

steinbach1.jpgIs it possible to extend a value type in C++? Alf Steinbach describes how to extend enum values.

Type Safe C++ enum Extensions

by Alf Steinbach

From the article:

Consider if an enum like the following,

  enum class Suit{
  spades, hearts, diamonds, clubs };

could be extended like

  enum class Suit_with_joker extends Suit {
    joker };

where

  • Suit_with_joker has all the enumerators of Suit plus the joker enumerator; and
  • enumerators introduced in Suit_with_joker get integer values following those of Suit; and
  • any Suit value is also a Suit_with_joker value.

This would be an example of what I’ll call a value type extension.

The apparently backwards is-a relationship in the last point, where any value of the original type is-a value of the derived type, is characteristic of value type extensions.

C++20 totally lacks support for value type extensions, of enum types or other types.

It’s Great That You Provide Operator Overloads, But It’s Also Nice to Have Names -- Raymond Chen

RaymondChenPic.pngOperator overloading. Looks great. Reduces verbosity. Until it doesn’t.

It’s Great That You Provide Operator Overloads, But It’s Also Nice to Have Names

by Raymond Chen

From the article:

Consider this overloaded function call operator:

struct StorageLoader
{
    template<DataType>
    DataType operator()(StorageOptions<DataType> const* options);
};

The idea is that you can use the function call operator on a Storage­Loader object to load data from storage, using a StorageOptions to describe how you want it to be loaded.

 

Object Lifetime -- Ilya Doroshenko

Today, we are going to talk about an object. Without further ado, let’s dive deeper!

Object Lifetime

by Ilya Doroshenko

From the article:

What is an object? According to the C++ standard, part 3.9.8 under the name of [basic.types]

 An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not a void type.

Now is int i an object? Yes.

Is void* p an object? Still yes, because pointers are types themselves, they are not references.

As we said, references are not types, but what if we declare something like struct S{ int& ref;}; would that be an object type? 

 

Dealing with Mutation: Guarded Suspension -- Rainer Grimm

dealingwithmutation.pngGuarded Suspension applies a unique strategy to deal with mutation. It signals when it is done with its modification.

Dealing with Mutation: Guarded Suspension

by Rainer Grimm

From the article:

The guarded suspension basic variant combines a lock and a precondition that must be satisfied. If the precondition is not fulfilled, that checking thread puts itself to sleep. The checking thread uses a lock to avoid a race condition that may result in a data race or a deadlock.

Various variants of the Guarded Suspension exist:

  • The waiting thread can passively be notified about the state change or actively ask for the state change. In short, I call this push versus pull principle.
  • The waiting can be done with or without a time boundary.
  • The notification can be sent to one or all waiting threads.

I present in this post only the rough idea. Let me start with the push principle.

You often synchronize threads with a condition variable or a future/promise pair. The condition variable or the promise sends the notification to the waiting thread. A promise has no notify_one or notify_all member function. Typically, a valueless set_value call is used to ...

C++17’s Useful Features for Embedded Systems -- Çağlayan Dökme

caglayan.pngRecently, our team at Meteksan Defense is upgrading its development environment to use newer versions of many tools and programming languages. One of the more difficult transitions has been the upgrade of our C++11 code base to C++17 for our embedded applications.

In this article, I will be showing some features of C++17 that can also be helpful in the embedded world.

C++17’s Useful Features for Embedded Systems

by Çağlayan Dökme

From the article:

C++14 had smaller upgrades compared to the ones we saw when migrating to C++11 from C++03. Hence, there are only a few features in C++14 that you can use in an embedded system.

Binary Literals

If you are frequently dealing with bitwise operations and modifying registers, you will love these literals. Some compilers had extensions that support such literals, but now they have a place in the actual standard.

uint8_t a = 0b110; // == 6 
uint8_t b = 0b1111'1111; // == 255 

Constraint relaxed constexpr**

With C++14, the syntax you can use in a constexpr function is expanded. Check out this post on StackOverflow. The constexpr is beneficial in the embedded world since...