/images/p1.jpg

Hi, I'm Tomasz

I'm a professional C++ software engineer with over a decade of hands on development experience with variety of technologies (mostly Linux & embedded systems). This is my blog.

Find me on social media

Experimenting with asynchronous IO

I haven’t got a chance yet to play with asynchronous I/O APIs in any production application so, to fill in that gap I’ve decided to commit some time and experiment with posix AIO and liburing a try. These two are (I think?), at the time of writing, the two most popular APIs to perform asynchronous operations in Linux.

This post isn’t a benchmark nor a comparison between the two. It’s just a knowledge summary of the basics behind using these APIs and what I’ve learned along the way.

Parsing user-agent strings and go:embed

I’m currently in the process of writing a back-end for a small web application that I plan to deploy in my local environment. The application isn’t really relevant. The important bit is a new trick I learned while working on it.

Within the back-end, at some point, I’m parsing an user-agent string. These strings are standardised and should follow the format described by HTTP Semantics.

For convenience, I’ve chosen to go with uap-go to parse these strings and here lies the catch.

Capturing raw `this` pointer is almost always a bad idea

Lifetime problems

As a reminder, I want to start with a classic example of using an invalid this captured in a lambda acting as a delegate .

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <functional>
#include <iostream>
#include <memory>
#include <string>

class Item {
public:
    explicit Item(std::string name) :
        name{name}
    {}

    std::function<void()> makeHelloDelegate() {
        return [this]{ hello(); };
    }

    void hello() const {
        std::cout << "item: " << name << std::endl;
    }

private:
    std::string name;
};


int main() {
    auto item = std::make_unique<Item>("pencil");

    auto d = item->makeHelloDelegate();

    item.reset();

    // `this` captured in lambda is now invalid

    // undefined behaviour (SIGSEGV most likely)
    d();

    return 0;
}

This is a classic lifetime issue. The object is destroyed but its this pointer is still captured in lambda. An attempt to call the delegate d will be essentially, a use after free leading to undefined behaviour.

C11 and C23 feature highlights

This is a short overview of things added along with c11 and c23 which I find useful or interesting.

auto keyword… yet again

auto has been repurposed in C23. Originally, it defined a storage duration for local variables (similarly as static) now, comparably as in C++, it can be used for type inference purposes.

1
2
3
4
5
6
7
void foo() {
    // auto is implied
    int i = 123;

    // same thing, auto keyword is redundant
    auto int j = 123;
}

In its original purpose, variables marked with auto have their storage automatically allocated and deallocated on scope entry and exit. It was implied for all local, stack variables. No one really used auto explicitly because it was just unnecessary now, it has an extra meaning.

C++ quick tips: Concepts, type constraints and c++20 coding style

c++20 introduced concepts to the standard thanks to which now, we can specify constraints and restrictions on template parameters that a given type, variable or a function template accepts. Similarly as with e.g. virtual classes defining interfaces for a family of types through inheritance, concepts allow creating interfaces for generic code. With concepts, just by looking at the template declaration we know what to expect and what types are accepted. Having a simple template like:

Of common problems with shared pointers

There’s one repeating pattern in all C++ code bases I’ve worked with. shared_ptr is abused - one way or another. There are many reasons, sometimes people just start with shared_ptr instead of unique_ptr out of laziness, sometimes it’s the sole, default smart pointer they rely on. Often, it’s a result of many passes of refactoring and eventual quality degradation with time. This leads to all sorts of problems but there’s are definitely some repeating patterns.

#3 The state of C++ package management: The build systems

Welcome to the third and concluding part of the series about dependency and package management in C++ projects in which I’m gonna mostly focus on solutions built into build systems themselves. If you haven’t already, I encourage you to have a quick read of the first and the second part.

Overview

In this part I’ll have a closer look on meson wraps, cmake’s FetchContent, bazel’s central registry and, a bit unconventionally, conda.