Articles & Books

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...

Inside STL: Smart Pointers -- Raymond Chen

RaymondChen_5in-150x150.jpgThe C++ standard library comes with a few smart pointer types. The simplest one is unique_ptr: This class babysits a raw pointer and remembers to delete it at destruction (in an appropriate manner). Dumping the contents of a unique_ptr is just looking at the raw pointer inside.

Inside STL: Smart Pointers

By Raymond Chen

From the article:

The C++ standard library comes with a few smart pointer types.

The simplest one is unique_ptr: This class babysits a raw pointer and remembers to delete it at destruction (in an appropriate manner). Dumping the contents of a unique_ptr is just looking at the raw pointer inside.

The complication is that there is also a deleter object in the unique_ptr. This deleter object is usually an empty class, so it is stored as part of a compressed pair.

The Visual Studio debugger has a visualizer that understands unique_ptr, but here’s what it looks like at a low level in the Microsoft implementation:

0:000< ?? p
class std::unique_ptr<S,std::default_delete<S> >
   +0x000 _Mypair          : std::_Compressed_pair<std::default_delete<S>,S *,1>
0:000< ?? p._Mypair
class std::_Compressed_pair<std::default_delete<S>,S *,1>
   +0x000 _Myval2          : 0x0000020a`11f08490 S
0:000< ?? p._Mypair._Myval2
struct S * 0x0000020a`11f08490 ← here is the unique object
   +0x000 a                : 0n42

Inside STL: The array -- Raymond Chen

RaymondChen_5in-150x150.jpgThe C++ standard library array is just a C-style array wrapped inside a class so that it behaves like a normal C++ object instead of a wacky thing that undergoes decay.

Inside STL: The array

By Raymond Chen

From the article:

template<typename T, size_t N>
class array
{
    T elements[N];
};

template<typename T>
class array<T, 0>
{
};

The only weird case is N = 0. You are allowed to create a zero-length std::array, but C++ does not allow zero-length C-style arrays. The zero-length std::array is just an empty class.

Visual Studio and the Windows debugger come with a visualizer:

0:000> dx a
a                : { size=5 } [Type: std::array<int,5>]
    [<Raw View>]     [Type: std::array<int,5>]
    [0]              : 3 [Type: int]
    [1]              : 1 [Type: int]
    [2]              : 4 [Type: int]
    [3]              : 1 [Type: int]
    [4]              : 5 [Type: int]

Meeting C++ 2023 - the last online conference?

Highlighting the online part of Meeting C++ 2023

Meeting C++ 2023 - the last online conference?

by Jens Weller

From the article:

A few days ago it caught my attention that Meeting C++ 2023 would be the last C++ organisation with an online part of its conference.

This is the case because last year the online part did find its interest in the C++ community. I think it serves the goals of Meeting C++ to continue an online presence for the conference as long as this is feasible...

C++20 Dynamic Allocations at Compile-time -- Andreas Fertig

logo.pngPeople often say constexpr all the things. Andreas Fertig shows where we can use dynamic memory at compile time.

C++20 Dynamic Allocations at Compile-time

By Andreas Fertig

From the article:

You may already have heard and seen that C++20 brings the ability to allocate dynamic memory at compile-time. This leads to std::vector and std::string being fully constexpr in C++20. In this article, I like to give you a solid idea of where you can use that.

How does dynamic allocation at compile-time work?

First, let’s ensure that we all understand how dynamic allocations at compile-time work. In the early draft of the paper ‘Standard containers and constexpr’ [P0784R1], proposed so-called non-transient allocations. They would have allowed us to allocate memory at compile-time and keep it to run-time. The previously allocated memory would then be promoted to static storage. However, various concerns did lead to allowing only transient allocations. That means what happens at compile-time stays at compile-time. Or in other words, the dynamic memory we allocate at compile-time must be deallocated at compile-time. This restriction makes a lot of the appealing use-cases impossible. I personally think that there are many examples out there that are of only little to no benefit.

Passkey Idiom: A Useful Empty Class -- Arne Mertz

logo.pngHow do you share some but not all of a class? Arne Mertz introduces the passkey idiom to avoid exposing too much with friendship.

Passkey Idiom: A Useful Empty Class

By Arne Mertz

From the article:

Let’s have a look at an example for useful empty classes. The passkey idiom can help us regain the control that we give up by simply making classes friends.

The problem with friendship

Friendship is the strongest coupling we can express in C++, even stronger than inheritance. So, we’d better be careful and avoid it if possible. But sometimes we just can’t get around giving one class more access than another.

A common example is a class that has to be created by a factory. The factory needs access to the class’s constructors. Other classes should not have that access so as not to circumvent the bookkeeping or whatever else makes the factory necessary.

The problem with the friend keyword is that it gives access to everything. There is no way to tell the compiler that the factory should not have access to any other private elements except the constructor. It’s all or nothing. 

Inside STL: The deque, implementation -- Raymond Chen

RaymondChen_5in-150x150.jpgNow that we understand the design behind the common STL dequeue implementations, we can peek into the implementation details.

Inside STL: The deque, implementation

By Raymond Chen

From the article:

All three of the major implementations of the standard library maintain an array of pointers to blocks, which they confusingly call a “map” even though it is unrelated to std::map. (Even more confusingly, gcc internally uses the term “node” instead of “block”.) Initially, all the pointers in the map are nullptr, and the blocks are allocated only on demand.

We will say that a block is spare if it contains only spare elements.