Articles & Books

Beware of Unsafe Conversions from size_t to int -- Giovanni Dicanio

When you have a size_t value and need to convert it to an int (for example: to pass it to a function expecting an int parameter), your C++ compiler may emit a warning message, and you may quickly silence it with a static_cast<int>. But, is that really safe? Or could that hide some subtle and "interesting" bugs?

Beware of Unsafe Conversions from size_t to int

by Giovanni Dicanio

From the article:

You can have some fun experimenting with these kinds of bugs with this simple C++ code [...]

So, these conversions from size_t to int can be dangerous and bug-prone, in both 32-bit and 64-bit builds.

 

On Writing Loops in Continuation-passing Style, Part 4 -- Raymond Chen

RaymondChen_5in-150x150.jpgIn this article, we delve into the equivalent helper functions for C# and JavaScript, which are simpler due to the inherent behavior of references in these languages, eliminating the need for explicit shared pointer conversions. 

On Writing Loops in Continuation-passing Style, Part 4

By Raymond Chen

From the article:

So far, we’ve been look at writing loops in PPL and continuation-passing style, and a lot of the complications came from creating shared_ptrs to manage shared state without copying, and trying to reduce the number of such pointers we had to make. The equivalent helper functions in C# and JavaScript are simpler because in those languages, references act like shared_ptr already; there’s no need to convert them into shared pointers explicitly.

class TaskHelpers
{
    public static Task DoWhileTask(Func<Task<bool>> callable)
    {
        return callable().ContinueWith(t =>
            t.Result ? DoWhileTask(callable)
                     : Task.CompletedTask).Unwrap();
    }
}

The C# Task Parallel Library’s ContinueWith method is the equivalent to the PPL then() method: You give it a Func<Task<T>, Result> which is called with the preceding task. In our case, we are given a Task<bool>: We check the result, and if it is true, then we recurse back and do the whole thing again.

The gotcha is that ContinueWith returns a task whose result type matches the return value of the Func you passed in. In our case, that Func returns a Task, so the return value of ContinueWith is a rather confusing Task<Task>. You need to follow up with the Unwrap() method to unwrap one layer and get a Task back. (More generally, the Unwrap method converts a Task<Task<T>> to a Task<T>.)

Optional Polymorphism by Delegation -- Daniel Lindner

softwareschmiede_logo-1-300x138.pngA code design pattern I’ve used a lot in recent times is the “optional-based polymorphism” that looks like a delegation to another type that might not be available. It might be an implementation of the FCoI-principle (Favour Composition over Inheritance).

Optional Polymorphism by Delegation

By Daniel Lindner

From the article:

Let’s look at an example: An application has several different engines that move stuff around. Some engines are based on limit switches. They move until they are stopped by a physical switch. The application can make these engines move from one predefined position to the next, but not anywhere in between. Another type of engines is based on a relative position. You give the engine the new target position and it positions itself there, without any limit switches or predefined positions.

Traditional approach

A typical implementation using inheritance would be a common supertype “Engine” that provides the functionality both engine types exhibit. From there, we would define two subtypes that extend the functionality in their desired way. One subtype would be the “LimitSwitchEngine”, the other one the “PositionableEngine”.

Our client code that wants to use a particular engine has two possibilities: It only requires the common functionality of an engine and can work with the supertype. Or it needs to perform a downcast after checking the actual type of the engine.

On Writing Loops in PPL and Continuation-passing Style, Part 3 -- Raymond Chen

RaymondChen_5in-150x150.jpgIn our previous discussion, we optimized a task-based while loop by eliminating nested shared pointers, instead requiring all the state to reside inside a caller-provided shared_ptr, making the callable stateless. This approach simplifies the code and reduces redundancy in managing state.

On Writing Loops in PPL and Continuation-passing Style, Part 3

By Raymond Chen

From the article:

Last time, we wrote a task-based while loop using recursion, using a shared_ptr to pass state, and we noted a redundancy in that we created a shared_ptr to a lambda that in turn held a shared_ptr.

We can eliminate the nested shared pointers by requiring that all the state live inside a caller-provided shared_ptr, levaing the callable stateless.

template<typename State>
task<void> do_while_task(
    std::shared_ptr<State> const& state,
    bool (*f)(std::shared_ptr<State> const&)
{
    return f(state).then([state, f](bool loop) {
        return loop ? do_while_task(state, f) :
                      task_from_result();
    });
}

struct lambda_state
{
    lambda_state(Widgets* w) : widgets(w) {}
    Widgets* widgets;
    int i = 0;
};

auto state = std::make_shared<lambda_state>(widgets);

do_while_task(state, [](auto&& state)
{
    if (state->i >= 3) return task_from_result(false);
    return create_widget().then([state](auto widget)
    {
        state->widgets[state->i] = widget;
        state->i++;
        return true;
    }
}).then([] {
    printf("Done!\n");
});

We can get rid of all the state-> prefixes by making the state be invocable.

Beautiful C++: 30 Core Guidelines... Book Review -- Bartlomiej Filipek

beautiful_cpp.jpgThis is a book review of “Beautiful C++,” written by two well-known C++ experts and educators: Kate Gregory and Guy Davidson. The book’s unique style gives us a valuable perspective on effective and safe C++ code.

Beautiful C++: 30 Core Guidelines... Book Review

By Bartlomiej Filipek

From the review:

The book is split into five parts, and each part has six guidelines to help us understand the material more easily.

  • Part one: Bikeshedding is bad - how to reduce the number of lines of your code and simplify it. For example, by using use in-class member initializers or avoiding getters and setters.
  • Part two: Don’t hurt yourself - how to avoid messy code and minimize complexity. For example, by limiting explicit sharing of variables, proper use of ABI and more.
  • Part three: Stop using that - some important bugs and bad C++ code style: singletons, casting away const or unsafe managing the ownership of resources.
  • Part four: Use this new thing properly - efficient use of modern C++ style: enum classes, constexpr, templates.
  • Part five: Write code well by default - good patterns for your code: type safety, immutable data structures avoiding uninitialized variables, and RAII.

In total, it’s around 300 pages + afterword and index.

If we look at a corresponding guideline like I.3: Avoid singletons you’ll see a short paragraph of introduction, some small example and a short discussion to alternatives. On the other hand, in the book, this guideline consists of 9 pages with unique examples, backstories, alternatives and discussions. The section shows things like:

  • Why global objects are bad
  • Singleton Design pattern overview
  • Static initialization order fiasco
  • Hiding singletons and making a namespace rather than a class
  • And even how to use constexpr in some cases (constexpr is also covered in other sections)

On Writing Loops in PPL and Continuation-passing Style, Part 2 -- Raymond Chen

RaymondChen_5in-150x150.jpgIn our previous discussion, we explored a task-based while loop employing custom callables that passed copies of themselves to the next iteration, which follows the continuation-passing style used in the Parallel Patterns Library (PPL). In this session, we will implement the same function using a more traditional recursive approach, aiming to simplify the sharing of state between lambda callables in PPL-style programming.

On Writing Loops in PPL and Continuation-passing Style, Part 2

By Raymond Chen

From the article:

Last time, we came up with task-based while loop that involved creating a custom callable that passed copies of itself to the next iteration.

This time, we’ll implement the function in terms of a more traditional recursion.

template<typename Callable>
task<void> do_while_task(
    std::shared_ptr<Callable> const& f)
{
    return (*f)().then([f](bool loop) {
        return loop ? do_while_task(f) :
                      task_from_result();
    });
}

template<typename Callable, typename =
    std::enable_if_t<std::is_invocable_v<Callable>>>
task<void> do_while_task(Callable&& callable)
{
    using Decayed = std::decay_t<Callable>;
    return do_while_task(
        std::make_shared<Decayed>(
            std::forward<Callable>(callable)));
}

The real work happens in the first overload, which takes a ready-made shared_ptr. The second overload is a convenience method that lets you pass a callable, and it will wrap it in a shared_ptr for you.

On Writing Loops in PPL and Continuation-passing Style, Part 1 -- Raymond Chen

RaymondChen_5in-150x150.jpgThe Parallel Patterns Library (PPL) relies on a continuation-passing style for asynchronous programming, where tasks are invoked and then linked to callable objects that process their results. This approach was the primary method for handling asynchronous operations before the introduction of await and co_await keywords in C#, JavaScript, and C++, making it essential to understand for developers working with older code or scenarios that still employ this style.

On Writing Loops in PPL and Continuation-passing Style, Part 1

By Raymond Chen

From the article:

The Parallel Patterns Library (PPL) is based on a continuation-passing style, where you invoke a task, and then attach a callable object that will be given the result. Prior to the introduction of the await and co_await keywords to C#, JavaScript, and C++, this was your only real choice for asynchronous programming.

Sequential calculations are fairly straightforward in continuation-passing style because you just pass the next step as the continuation.

// Synchronous version
auto widget = find_widget(name);
auto success = widget.toggle();
if (!success) report_failure();

// Asynchronous version
find_widget(name).then([=](auto widget) {
    return widget.toggle();
}).then([=](auto success) {
    if (!success) report_failure();
});

Iteration is harder to convert to continuation-passing style because you need to restart the task chain, which means you have recursion.

Inside STL: The Different Types of Shared Pointer Control Blocks -- Raymond Chen

RaymondChen_5in-150x150.jpgIn the realm of C++ standard library shared pointers, a crucial component for managing object lifetime is the control block, which contains reference count information and instructions for disposal and deletion. Depending on whether you use make_shared, allocate_shared, or manually assign an already-constructed pointer, different types of control blocks come into play, each with its own characteristics and optimizations for efficiently handling object management.

Inside STL: The Different Types of Shared Pointer Control Blocks

By Raymond Chen

From the article:

We saw earlier that C++ standard library shared pointers use a control block to manage the object lifetime.

struct control_block
{
    virtual void Dispose() = 0;
    virtual void Delete() = 0;
    std::atomic<unsigned long> shareds;
    std::atomic<unsigned long> refs;
};

The control block has pure virtual methods, so it is up to derived classes to establish how to dispose and delete the control block.

If you ask a shared_ptr to take responsibility for an already-constructed pointer, then you get this:

template<typename T>
struct separate_control_block : control_block
{
    virtual void Destroy() noexcept override
    {
        delete ptr;
    }
    virtual void Delete() noexcept override
    {
        delete this;
    }
    T* ptr;
};