Blog

Inside STL: Waiting for a std::atomic to change, part 1 -- Raymond Chen

RaymondChen_5in-150x150.jpgWhen using std::atomic<std::shared_ptr<T>>, the C++ standard defines a "change" as a modification to either the stored pointer or the control block pointer. However, since atomic wait mechanisms typically track only a single memory address, the Microsoft implementation handles this limitation by using a timeout-based polling strategy to detect changes in the control block.

Inside STL: Waiting for a std::atomic<std::shared_ptr<T>> to change, part 1

by Raymond Chen

From the article:

Like other std::atomic specializations, std::atomic<std::shared_ptr<T>> supports the wait and notify_* methods for waiting for the value to change and reporting that the value has changed. The definition of “changed” in the C++ language specification is that the value has changed if either the stored pointer or the control block pointer has changed. A shared pointer is implemented as a pair of pointers, but Wait­On­Address can wait on at most 8 bytes, and unix futexes can wait on only four bytes, so how does this work?¹

The Microsoft implementation waits for the stored pointer to change, and the notify_* methods signal the stored pointer. But wait, this fails to detect the case where the stored pointer stays the same and only the control block changes.

std::atomic<std::shared_ptr<int>> p =
    std::make_shared<int>(42);

void change_control_block()
{
    auto old = p.load();
    auto empty = std::shared_ptr<int>();

    // Replace with an indulgent shared pointer
    // with the same stored pointer.
    p.store({ empty, old.get() });
    p.notify_all();
}

void wait_for_change()
{
    auto old = p.load();
    p.wait(old);
}

C++26: A Placeholder with No Name -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGIn this post, we are going to discuss a core language feature proposed by Corentin Jabot and Micheal Park in P2169R4. With the new standard we get a cool unnamed placeholder.

C++26: A Placeholder with No Name

by Sandor Dargo

From the article:

By convention, when we have a variable whose value we don’t want to use or care about, we often name it _. The problem is that with higher warning levels (-Wunused-variable), our compilation might fail because _ is unused.
int foo() {
return 42;
}

auto _ = foo();
/* error: unused variable '_' [-Werror,-Wunused-variable] */

To avoid this problem, we must mark it [[maybe_unused]].

 

PVS-Studio 7.35: MISRA C 2023 support, Qt Creator 15 plugin, and more

PVS-Studio 7.35 has been released. Support for the MISRA C standard, the plugin for Qt Creator 15.x, modified file analysis in Visual Studio, and that's not all.

PVS-Studio 7.35: MISRA C 2023 support, Qt Creator 15 plugin, and more

by Vladislav Bogdanov

From the article:

We've begun work to expand the PVS-Studio's coverage of the MISRA C standard. With the release of 7.35, the first eight diagnostic rules have already been implemented, and more are on the way. The full list of implemented rules is provided below. We plan to cover at least 85% of MISRA C and support the latest version of MISRA C 2023.

 

Write More C++ Code Thanks to constexpr -- Andreas Fertig

me.pngSince its introduction, the constexpr keyword in C++ has steadily evolved with each new standard, becoming an increasingly powerful tool for compile-time computation and optimization. In this article, I’ll share a real-world example of how constexpr helped optimize memory usage and improve performance for an embedded system project, showcasing its potential to transform how we approach C++ programming.

Write More C++ Code Thanks to constexpr

by Andreas Fertig

From the article:

Since the keyword constexpr and its behavior got included in C++, it has been improved in each and every new standard of the language.

I'm a big fan of constexpr and am not alone. Jason Turner is also very vocal, having coined the term "constexpr all the things".

Well, demonstrating the powers of constexpr is nonetheless something difficult. I know that from my training classes and various consulting contracts. Today, I'd like to share a story from back in time when a customer hired me to consult. They did develop an embedded system and ran out of memory. Not during run-time, but before. The features they wanted to put in the chip were too big in code size and somewhat RAM.

Initial constexpr-free example

They used a class I've seen a couple of times in embedded systems with some variations. A string brings its memory picky-back. 

 

 

Reverse Iterations -- Coral Kashri

c-senioreas-v9.pngSometimes, we all need a way to iterate over a container in the opposite direction. There are several ways to reverse-iterate a container, and in this article, we’ll explore them.

Reverse Iterations

by Coral Kashri

From the article:

Probably the simplest way, taken from C is to iterate using an index location:
for (int64_t index = ssize(container); index >= 0; --index) {
    // do something with `container[index]`
}
This way is highly not recommended as it might lead to infinite loops if done incorrectly (for example by using uint64_t or size_t for the index type), and you can find more issues with this way in some previous articles about iterators in this blog.

C++26: user-generated static_assert messages -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGstatic_assert further evolves with C++26. Our tool for compile-time assertion will support user-generated error messages. As such, we’ll be able to reuse messages as well as enrich them with information available at compile-time making diagnostics easier to read.

C++26: user-generated static_assert messages

by Sandor Dargo

From the article:

Our first quest into the world of C++26 was about =delete with an optional error message, which improves the readability of the source code and potentially the error messages. In this next part of our journey, we will continue to focus on readability improvements, particularly those for error messages.

With C++26 and the acceptance of P2741R3, we are getting better error messages for static_assert. Compile time assertions were introduced in C++11 with a mandatory message. Since C++17, the message is only optional. And with C++26, static_assert evolves further and the message can be a constant expression instead of an unevaluated string. In other words, it can have some dynamic elements.

This was not the first attempt to make such a feature part of C++, but back in 2014, when something similar was proposed, C++ didn’t have enough compile-time programming capabilities to make this easily implementable.

Why is this change useful?

Before looking at some concrete examples of utilisation, let’s dig into the motivations behind this feature.

Obviously, we want better error messages. C++ is infamous for its horrendous error logs when the compilation fails. Even though we must admit that it’s more and more just a legacy, the situation improved a lot over the course of the years. In any case, it was mostly template-related error messages that were behind the biggest issues.

While compile-time assertions with their custom messages already meant an improvement, user-generated diagnostic messages will further improve the situation.

But that’s not the only motivation. Sometimes you don’t want different, or better messages. You just want the same message in several assertions without having to duplicate it. Without this change, the following piece of code doesn’t compile:

The first Meeting C++ trainings in 2025

With the success of the trainings after Meeting C++ 2024, I've decided to offer more opportunities for you to learn C++. Klaus Iglberger starts next week with C++ Software Design.

With these trainings following in March:

    Generic programming in C++ with templates and auto with Nicolai Josuttis (10th March, 1 day)
    Embedded C++ Basic Training with Richard Kaiser (10th March, 4 days)
    C++ Fundamentals You Wish You Had Known Earlier with Mateusz Pusz (13th March, 2 days)
    Concepts, Ranges, and Views - The New Way of Programming in C++ with Nicolai Josuttis (17th March, 1 day)
    Introduction to C++ - Five Day Online Training with Slobodan Dmitrovic (24th March, 5 days)
    Structured Concurrency in C++: A Hands-On Workshop (Coroutines + Senders/Receivers) with Mateusz Pusz (24th March, 2 days)

My goal is to offer a good set of trainings within a certain time frame each quarter with changing trainers. Ideally all within one week, but that doesn't match out all the time.

 

8 More C++23 Examples -- Bartlomiej Filipek

filipek-8moreexamples.pngIn this article, you’ll see eight larger examples that illustrate the changes in C++23.

8 More C++23 Examples

by Bartlomiej Filipek

From the article:

C++23 brings a ton of cool features, as you can see in my two previous articles (here and here). So far, we explored each new addition one by one, but I’d like to share more examples that combine multiple features.

Here we go:

1. std::ranges::to<> 

The ranges::to<> feature allows you to convert ranges into containers easily:

filipek-8examples.png

In C++, failure to meet the requirements does not always mean that you fail -- Raymond Chen

RaymondChen_5in-150x150.jpgWhen tasked with diagnosing why a pointer passed through a pipeline emerged offset from its original value, I discovered an interesting culprit: the misuse of a wrapper function around SubmitWork. While the wrapper aimed to simplify usage by allowing both raw pointers and references to standard layout types, it inadvertently caused ambiguous overload resolution, leading to incorrect behavior. This analysis explores how the issue arose, the debugging process, and improvements to ensure robust and predictable pointer handling in similar scenarios.

In C++, failure to meet the requirements does not always mean that you fail if you don’t meet the requirements

by Raymond Chen

From the article:

I was asked to help debug a problem where a pointer passed to a function was received slightly offset from the original value. The pointer is passed as an opaque parameter and is supposed to be spit out the other end of a pipeline. But somehow, the value that came out the other end was slightly different.

For expository purposes, let’s say that the underlying function we’re trying to call is this one.

void SubmitWork(HWORKER worker, int commandCode, void* param);

You call Submit­Work with a worker, a command code, and a raw pointer to some data that depends on the command code.

The developer sent me some debugging output that showed that the function that handled the command code received a different pointer from what was passed. One possibility is that there was a bug in the library that resulted in it unintentionally modifying the final pointer parameter, but this seemed unlikely, since the value should be opaque to the library. I was able to get on a video call with the developer to watch them step through the code, and that’s where I noticed something interesting.

 

ADL – Avoid Debugging Later -- Coral Kashri

kashri-adl.pngBack in the day, being a witch was considered a grave crime. Today, we’re diving into one of C++’s lesser-known spells: ADL (Argument-Dependent Lookup). 

ADL – Avoid Debugging Later

by Coral Kashri

From the article:

But before we explore this arcane magic, you must heed a warning—black magic comes with consequences. ADL is particularly treacherous, often leading to frustrating and hard-to-debug issues. Whenever possible, it’s wise to avoid casting this spell unless absolutely necessary.

Ingredients

Every spell needs ingredients, this time the only ingredients you need are a C++ compiler and a function that accepts at least one parameter, but there is a try catch, the parameter type has to belong to the same namespace of the function.

This spell works in shadows—you must look closely to uncover its effect.

std::cout << "Can you see me?";

Should the spell have passed you by, I’ll summon its power again for your eyes:

std::vector<int> a{1}, b{2};
swap(a, b);

If the spell’s effect remains elusive, let’s summon the entire code for you to see:

#include <vector>

int main() {
    std::vector<int> a{1}, b{2};
    swap(a, b);
    return 0;
}