Articles & Books

Exploring ref qualifiers in C++

Recently I've been wondering about ref qualifiers in C++.

Exploring ref qualifiers in C++

by Jens Weller

From the article:

Ref qualifiers are today an old C++11 feature, and recently I wanted to know more about them. Especially their potential use cases.

Thats a particular point with this feature, I've seen examples - but often without a compelling use case. This feature is a great way to achieve very specific things in C++...

 

What reinterpret_cast doesn't do -- Andreas Fertig

Depositphotos_347968346_S.jpgIn today's post, I will explain one of C++'s biggest pitfalls: reinterpret_cast. Another title for this post could be: This is not the cast you're looking for!

What reinterpret_cast doesn't do

Andreas Fertig

From the article:

My motivation for this blog post comes from multiple training classes I thought over the past several months and a couple of talks I gave. Since C++23, you have a new facility in the Standard Library: std::start_lifetime_as. When teaching class with a focus on embedded environments or presenting talks with such a focus, I started to add std::start_lifetime_as to the material. With an interesting outcome.

The feedback I get is roughly:

  • why do I need std::start_lifetime_as, I already have reinterpret_cast?
  • why can I use reinterpret_cast?

If you never heard of start_lifetime_as please consider reading my post, The correct way to do type punning in C++ - The second act.

What Happens When a Destructor Throws -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGEven experienced C++ developers sometimes stumble on a deceptively simple question: what actually happens when a destructor throws an exception? This post breaks down the mechanics behind stack unwinding, noexcept, and why throwing from destructors is almost always a bad idea

What Happens When a Destructor Throws

by Sandor Dargo

From the article:

Recently I wrote about the importance of finding joy in our jobs on The Dev Ladder. Mastery and deep understanding are key elements in finding that joy, especially now that generating code is cheap and increasingly done better by AI than by us.

Then a memory surfaced. I frequently ask during interviews — as part of a code review exercise — what happens when a destructor throws. Way too many candidates, even those interviewing for senior positions, cannot answer the question. Most say it’s bad practice, but cannot explain why. Some say the program might terminate. Getting an elaborate answer is rare.

I’m not saying it’s a dealbreaker, but it definitely doesn’t help.

Let’s see what actually happens.

The role of a destructor

A destructor is the key to implementing the RAII idiom. RAII matters because after you acquire a resource, things might go south. A function might need to return early, or it might throw. Making sure resources are released is cumbersome, and the cleanest way to achieve it is to wrap both acquisition and release in an object that handles this automatically.

But what if the release itself is not successful?

Destructors have no return value, so error reporting is limited. Typical options include logging, storing error state, or (discouraged) throwing.

Why did I mark throwing an exception discouraged?

Evolving a Translation System with Reflection in C++

A nice example of C++26 reflection moving from theory into something practical.

Evolving a Translation System with Reflection in C++

By GitHub user: friedkeenan
 

From the post:

Lately, I’ve been using C++26 reflection to create some crazy and cursed stuff. But even though I quite enjoy that work, it is as well quite far from the norm of what reflection is going to offer us in our everyday code.

Reflection is definitely not just that craziness, and so I want to present reflection in a more grounded environment, and in a way that will probably land as more typical usage as our codebases gradually come into contact with it.

So then, in this blogpost, I will be exploring a spectrum of options for how reflection can upgrade a translation system that I already use in one of my projects. We’ll look at where it’s at now without reflection, identify places in which reflection could plausibly help, and then explore a series of modifications we could make to soothe those problem points.

The purpose of looking at each of these options will not be to declare that one is clearly the best option or the one that makes the most sense, but rather to get a better feel for what could make sense to do, and whether some things are really worth the effort. We’re trying to gauge the benefits that reflection can bring to our code.

And who knows, even if one option is less appealing for this particular situation, maybe in a different situation it could be the perfect fit.

C++26: A User-Friendly assert() macro -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGC++26 is bringing some long-overdue changes to assert(). But why are those changes needed? And when do we actually use assert, anyway?

At its core, assert() exists to validate runtime conditions. If the given expression evaluates to false, the program aborts. I’m almost certain you’ve used it before — at work, in personal projects, or at the very least in examples and code snippets.

So what’s the problem?

C++26: A User-Friendly assert() macro

by Sandor Dargo

From the article:

assert() is a macro — and a slightly sneaky one at that. Its name is written in lowercase, so it doesn’t follow the usual SCREAMING_SNAKE_CASE convention we associate with macros. There’s a good chance you’ve been using it for years without ever thinking about its macro nature.

Macros, of course, aren’t particularly popular among modern C++ developers. But the issue here isn’t the usual - but valid - “macros are evil” argument. The real problem is more specific:

The preprocessor only understands parentheses for grouping. It does not understand other C++ syntax such as template angle brackets or brace-initialization.

As a result, several otherwise perfectly valid-looking assertions fail to compile:

// https://godbolt.org/z/9sqM7PvWh
using Int = int;
int x = 1, y = 2;

assert(std::is_same<int, Int>::value);
assert([x, y]() { return x < y; }() == 1);
assert(std::vector<int>{1, 2, 3}.size() == 3);
 

 

Stackless coroutines for gamedev in ~200 lines of C++ -- Vittorio Romeo

C++20 coroutines have lovely syntax, but they're a terrible fit for games.

In this article, we'll build a macro-base alternative that's more suitable for game development in ~200 lines of C++.

Stackless coroutines for gamedev in ~200 lines of C++

by Vittorio Romeo

From the article:

For a game I want a coroutine that is part of an object’s data. When the object dies, the coroutine dies with it. When I serialize the object to a save buffer, the coroutine’s state goes with it. When the optimizer is off, there is no extra cost compared to the equivalent state machine. C++20 coroutines do not provide any of these guarantees out of the box.

Let’s build something that does.

Glaze 7.2 - C++26 Reflection | YAML, CBOR, MessagePack, TOML and more

Glaze is a high-performance C++23 serialization library with compile-time reflection. It has grown to support many more formats and features, and in v7.2.0 C++26 Reflection support has been merged!

Glaze 7.2 - C++26 Reflection | YAML, CBOR, MessagePack, TOML and more

From the article:

Glaze now supports C++26 reflection with experimental GCC and Clang compilers. GCC 16 will soon be released with this support. When enabled, Glaze replaces the traditional __PRETTY_FUNCTION__ parsing and structured binding tricks with proper compile-time reflection primitives (std::meta).

The API doesn't change at all. You just get much more powerful automatic reflection that still works with Glaze overrides! Glaze was designed with automatic reflection in mind and still lets you customize reflection metadata using glz::meta on top of what std::meta provides via defaults.

Behold the power of meta::substitute -- Barry Revzin

What if string formatting could do far more than just substitute values—and do it all at compile time? This deep dive explores how modern C++ features like reflection unlock powerful new possibilities for parsing, analyzing, and transforming format strings before your program even runs.

Behold the power of meta::substitute

by Barry Revzin

From the article:

Over winter break, I started working on proposal for string interpolation. It was a lot of fun to work through implementing, basically an hour a day during my daughter’s nap time. The design itself is motivated by wanting to have a lot more functionality other than just formatting — and one of the examples in the paper was implementing an algorithm that does highlighting of the interpolations, such that:

revzin-codeeg.png

 

 

 

would print this:

x=5 and y=*10* and z=hello!

without doing any additional parsing work. I got the example from Vittorio Romeo’s original paper.

Now, when I wrote the paper, I considered this to be a simple example demonstrating something that was possible with the design I was proposing that was not possible with the other design. I thought that because obviously you need the format string as a compile-time constant in order to parse it at compile time to get the information that you need.

Let's check vibe code that acts like optimized C++ one but is actually a mess

The value of a skilled developer is shifting toward the ability to effectively review code. Although generating code now is easier than ever, evaluating it for proper decomposition, correctness, efficiency, and security is still important. To see why it's important to understand generated code and to recognize what lies beneath a program's elegant syntax, let's look at a small project called markus, created using Claude Opus.

Let's check vibe code that acts like optimized C++ one but is actually a mess

by Andrey Karpov

From the article:

Clearly, the 64-bit code is much more efficient, except when SSE2 is involved. Even then, though, everything runs quickly. The code Claude Opus generated for the markus project is the worst of all the options. Not only is the simplest implementation with a regular loop faster, it's also shorter. The extra code lines only made things worse.

 

Devirtualization and Static Polymorphism -- David Álvarez Rosa

rosa-devirtualization.pngEver wondered why your clean, object-oriented design sometimes slows things down? This piece breaks down how virtual dispatch impacts performance—and how techniques like devirtualization and static polymorphism can eliminate that overhead entirely.

Devirtualization and Static Polymorphism

by David Álvarez Rosa

From the article:

Ever wondered why your “clean” polymorphic design underperforms in benchmarks? Virtual dispatch enables polymorphism, but it comes with hidden overhead: pointer indirection, larger object layouts, and fewer inlining opportunities.

Compilers do their best to devirtualize these calls, but it isn’t always possible. On latency-sensitive paths, it’s beneficial to manually replace dynamic dispatch with static polymorphism, so calls are resolved at compile time and the abstraction has effectively zero runtime cost.