October 2023

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;
};

SObjectizer Tales – 2. Can you call me back?--Marco Arena

A new episode of the series about SObjectizer and message passing:

SObjectizer Tales – 2. Can you call me back

by Marco Arena

From the article:

A camera vendor has just released a new SDK that works through callbacks. Basically, the user sets a function that will get called by the SDK on every new available frame. How can we integrate this into a producer agent?

How to Use Monadic Operations for `std::optional` in C++23 -- Bartlomiej Filipek

monadic_optional.pngIn this post we’ll have a look at new operations added to std::optional in C++23. These operations, inspired by functional programming concepts, offer a more concise and expressive way to work with optional values, reducing boilerplate and improving code readability.

How to Use Monadic Operations for `std::optional` in C++23

By Bartlomiej Filipek

From the article:

Let’s meet and_then()transform() and or_else(), new member functions.

Traditional Approach with if/else and optional C++20  

In C++20 when you work with std::optional you have to rely heavily on conditional checks to ensure safe access to the contained values. This often led to nested if/else code blocks, which could make the code verbose and harder to follow.

Consider the task of fetching a user profile. The profile might be available in a cache, or it might need to be fetched from a server. Once retrieved, we want to extract the user’s age and then calculate their age for the next year. 

Phantom and Indulgent Shared Pointers -- Raymond Chen

RaymondChen_5in-150x150.jpgIn our exploration of shared_ptr variations, we've previously covered cases where the stored pointer was either empty or pointed to a managed object. Now, we delve into the intriguing cases of phantom shared pointers, where the stored pointer is null but secretly manages an object, and indulgent shared pointers, which point to something but own nothing, offering unique utility for scenarios like static storage duration, with methods like use_count() and get() aiding in their detection.

Phantom and Indulgent Shared Pointers

By Raymond Chen

From the article:

Last time, we looked at various ways to convert among different shared_ptrs. We finished with this diagram:

2023-10-02_14-15-23.png

 

 

 

You are familiar with an empty shared pointer, which manages no object and has no stored pointer. You are also familiar with a full shared pointer, which manages an object and has a non-null stored pointer (to the managed object, or something whose lifetime is controlled by the managed object). But what about those other two guys?

In the upper right corner, you have the case of a shared pointer that manages an object but whose stored pointer is null, which I’ve called a phantom shared pointer. If you convert the shared pointer to a bool, it produces false, because you can’t use it to access anything. The phantom shared pointer looks empty at a casual glance, but it secretly manages an object behind the scenes. That secretly-managed object remains alive for no visible reason. There is no way to access that secretly-managed object, but it’s still there. It’s a phantom which follows you around.

SObjectizer Tales - 1. Producing Images--Marco Arena

A new episode of the series about SObjectizer and message passing:

SObjectizer Tales - 1. Producing Images

by Marco Arena

From the article:

Since using any real camera drivers is out of scope, we’ll use OpenCV to open our default camera (e.g. the webcam) and grab frames one by one. In case you don’t have any available camera on your machine, we’ll provide a simple “virtual producer” that replays some images from a directory...

What it means when you convert between different shared_ptrs -- Raymond Chen

RaymondChen_5in-150x150.jpgIn C++, the shared_ptr is commonly used to manage reference-counted pointers, typically pointing to objects that get deleted when the last reference expires. However, it's possible to create shared_ptr instances where the managed object and the stored pointer are different, enabling scenarios like accessing sub-objects or creating aliasing shared pointers. This article explores various ways to achieve this, including type conversions and special helper functions like static_pointer_cast, const_pointer_cast, reinterpret_pointer_cast, and dynamic_pointer_cast, shedding light on some nuances in the process.

What it means when you convert between different shared_ptrs

By Raymond Chen

From the article:

The C++ shared_ptr manages a reference-counted pointer. Usually, it’s a pointer to an object that will be delete‘d when the last reference expires. But it doesn’t have to be that way.

Recall that a shared_ptr is really two pointers.

  • A pointer to a control block which manages the shared and weak reference counts, and which destroys an object (commonly known as the managed object) when the shared reference count drops to zero.
  • A pointer to return from the get() method, commonly know as the stored pointer.

Most of the time, the stored pointer points to the managed object, because that what you get when you construct a shared_ptrs from a raw pointer or when you call make_shared. But what is the use case for a shared_ptr where the managed object and the stored pointer are different?

 

Inside STL: The shared_ptr constructor and enable_shared_from_this -- Raymond Chen

RaymondChen_5in-150x150.jpgIn C++, when you create a class that derives from std::enable_shared_from_this, it becomes eligible for special treatment by shared_ptr, allowing the shared_from_this() method to return a shared_ptr to the object. However, certain conditions and constraints must be met, and this functionality is enabled through a mechanism involving a secret weak pointer called weak_this.

Inside STL: The shared_ptr constructor and enable_shared_from_this

By Raymond Chen

From the article:

If you create a class of the form

struct S : std::enable_shared_from_this<S>
{
    /* ... */
};

which derives from std::enable_shared_from_this of itself (using the curiously recurring template pattern), then this class becomes a candidate for special treatment by shared_ptr: The shared_from_this() method will produce a shared_ptr<S>. Some restrictions apply.

Inside STL: The shared_ptr constructor vs make_shared -- Raymond Chen

RaymondChen_5in-150x150.jpgThis article discusses the memory layouts when creating an object controlled by a shared_ptr in C++ through two methods: using a raw pointer and via the make_shared function. 

Inside STL: The shared_ptr constructor vs make_shared

By Raymond Chen

From the article:

There are two ways to create a new object that is controlled by a shared_ptr.

// From a raw pointer
auto p = std::shared_ptr<S>(new S());

// Via make_shared
auto p = std::make_shared<S>();

They result in two different memory layouts.

In the first case, you manually created a new S object, and then passed a pointer to it to the shared_ptr constructor. The shared_ptr adopts the raw pointer and creates a control block to monitor its lifetime. When the last shared pointer destructs, the Dispose() method deletes the pointer you passed in.¹ When the last shared or weak pointer destructs, the Delete() method deletes the control block.

SObjectizer Tales - Prelude--Marco Arena

A new blog series about SObjectizer and message passing:

SObjectizer Tales - Prelude

by Marco Arena

From the article:

Some time ago, I was looking for alternatives to Microsoft’s Asynchronous Agents Library. I developed a Windows application interfacing with industrial cameras and performing multiple tasks such as visualization and object recognition...

2023-09 Mailing Available

The 2023-09 mailing of new standards papers is now available.

 

WG21 Number Title Author Document Date Mailing Date Previous Version Subgroup
P0843R9 inplace_vector Gonzalo Brito Gadeschi 2023-09-14 2023-09 P0843R8 LEWG Library Evolution,LWG Library
P1068R9 Vector API for random number generation Ilya Burylov 2023-09-14 2023-09 P1068R8 LEWG Library Evolution
P1255R10 A view of 0 or 1 elements: views::maybe Steve Downey 2023-09-14 2023-09 P1255R9 SG9 Ranges,LEWG Library Evolution
P2264R5 Make assert() macro user friendly for C and C++ Peter Sommerlad 2023-09-13 2023-09 P2264R4 LEWG Library Evolution,LWG Library
P2542R4 views::concat Hui Xie 2023-09-11 2023-09 P2542R3 SG9 Ranges,LEWG Library Evolution
P2542R5 views::concat Hui Xie 2023-09-12 2023-09 P2542R4 SG9 Ranges,LEWG Library Evolution,LWG Library
P2686R2 constexpr structured bindings and references to constexpr variables Corentin Jabot 2023-09-14 2023-09 P2686R1 EWG Evolution,CWG Core
P2748R2 Disallow Binding a Returned Glvalue to a Temporary Brian Bi 2023-09-14 2023-09 P2748R1 EWG Evolution
P2755R0 A Bold Plan for a Complete Contracts Facility Joshua Berne, Jake Fevold, John Lakos 2023-09-13 2023-09   SG21 Contracts
P2760R0 A Plan for C++26 Ranges Barry Revzin 2023-09-17 2023-09   SG9 Ranges,LEWG Library Evolution
P2762R1 Sender/Receiver Interface For Networking Dietmar Kuhl 2023-09-15 2023-09 P2762R0 SG4 Networking,LEWG Library Evolution
P2833R2 Freestanding Library: inout expected span Ben Craig 2023-09-13 2023-09 P2833R1 LWG Library
P2846R1 size_hint: Eagerly reserving memory for not-quite-sized lazy ranges Corentin Jabot 2023-09-15 2023-09 P2846R0 LEWG Library Evolution
P2865R3 Remove Deprecated Array Comparisons from C++26 Alisdair Meredith 2023-09-14 2023-09 P2865R2 SG22 Compatability,CWG Core
P2866R1 Remove Deprecated Volatile Features From C++26 Alisdair Meredith 2023-09-15 2023-09 P2866R0 SG1 Concurrency and Parallelism,SG22 Compatability,LEWG Library Evolution
P2867R1 Remove Deprecated strstreams From C++26 Alisdair Meredith 2023-09-15 2023-09 P2867R0 LEWG Library Evolution
P2868R2 Remove Deprecated `std::allocator` Typedef From C++26 Alisdair Meredith 2023-09-14 2023-09 P2868R1 LEWG Library Evolution
P2869R2 Remove Deprecated `shared_ptr` Atomic Access APIs From C++26 Alisdair Meredith 2023-09-15 2023-09 P2869R1 LEWG Library Evolution
P2870R2 Remove `basic_string::reserve()` From C++26 Alisdair Meredith 2023-09-14 2023-09 P2870R1 LEWG Library Evolution
P2871R2 Remove Deprecated Unicode Conversion Facets From C++26 Alisdair Meredith 2023-09-15 2023-09 P2871R1 LEWG Library Evolution
P2872R2 Remove `wstring_convert` From C++26 Alisdair Meredith 2023-09-14 2023-09 P2872R1 LEWG Library Evolution
P2875R2 Undeprecate `polymorphic_allocator::destroy` For C++26 Alisdair Meredith 2023-09-15 2023-09 P2875R1 LEWG Library Evolution
P2885R2 Requirements for a Contracts syntax Timur Doumler 2023-08-29 2023-09 P2885R1 SG21 Contracts,EWG Evolution
P2909R1 Fix formatting of code units as integers (Dude, where's my char?) Victor Zverovich 2023-09-05 2023-09 P2909R0 LEWG Library Evolution
P2909R2 Fix formatting of code units as integers (Dude, where's my char?) Victor Zverovich 2023-09-16 2023-09 P2909R1 LWG Library
P2932R0 A Principled Approach to Open Design Questions for Contracts Joshua Berne 2023-09-13 2023-09   SG21 Contracts
P2935R1 An Attribute-Like Syntax for Contracts Joshua Berne 2023-09-15 2023-09 P2935R0 SG21 Contracts
P2935R2 An Attribute-Like Syntax for Contracts Joshua Berne 2023-09-15 2023-09 P2935R1 SG21 Contracts
P2944R2 Comparisons for reference_wrapper Barry Revzin 2023-09-17 2023-09 P2944R1 LEWG Library Evolution
P2951R3 Shadowing is good for safety Jarrad J. Waterloo 2023-09-02 2023-09 P2951R2 SG23 Safety and Security
P2955R1 Safer Range Access Jarrad J. Waterloo 2023-09-02 2023-09 P2955R0 LEWGI SG18: LEWG Incubator,SG23 Safety and Security
P2961R0 A natural syntax for Contracts Jens Maurer 2023-09-17 2023-09   SG21 Contracts
P2963R0 Ordering of constraints involving fold expressions Corentin Jabot 2023-09-15 2023-09   EWG Evolution
P2966R0 Making C++ Better for Game Developers -- Progress Report Patrice Roy 2023-09-05 2023-09   SG14 Low Latency,EWG Evolution
P2966R1 Making C++ Better for Game Developers -- Progress Report Patrice Roy 2023-09-13 2023-09 P2966R0 SG14 Low Latency,EWG Evolution
P2968R0 Make std::ignore a first-class object Peter Sommerlad 2023-09-07 2023-09   LEWG Library Evolution,LWG Library
P2971R0 Implication for C++ Walter E Brown 2023-09-14 2023-09   EWG Evolution
P2972R0 2023-09 Library Evolution Polls Inbal Levi 2023-09-17 2023-09   LEWG Library Evolution,LWG Library
P2973R0 Erroneous behaviour for missing return from assignment Thomas Köppe 2023-09-15 2023-09   SG12 Undefined and Unspecified Behavior,SG23 Safety and Security,EWG Evolution,CWG Core
P2976R0 Freestanding Library: algorithm, numeric, and random Ben Craig 2023-09-17 2023-09   LEWG Library Evolution