Articles & Books

Optimizing the Unoptimizable: A Journey to Faster C++ Compile Times -- Victor Zverovich

zverovich-compiletimes.jpgIn this post, Victor talks about bringing compile times of the {fmt} library on par with the C standard I/O library (stdio).

Optimizing the Unoptimizable: A Journey to Faster C++ Compile Times

by Victor Zverovich

From the article:

First some background: {fmt} is a popular open-source formatting library for C++ that provides a better alternative to C++ iostreams and C stdio. It has already surpassed stdio in many areas:

  • Type safety with compile-time format string checks available by default since C++20 and as an opt in for C++14/17. Runtime format strings are also safe to use in {fmt} which is impossible to achieve in printf.
  • Extensibility: user-defined type can be made formattable and most standard library types such as containers, dates and times are formattable out of the box.
  • Performance: {fmt} is significantly faster than common standard library implementations of printf, in some cases by an order of magnitude (e.g. on floating-point formatting).
  • Portable Unicode support.

However, one area where stdio remained significantly better was compile times. 

The Case of the Vector With an Impossibly Large Size -- Raymond Chen

RaymondChen_5in-150x150.jpgIn this software troubleshooting case, a customer experienced program crashes, and a detailed analysis of the code revealed several issues. The primary problem stemmed from lazy initialization of a widget list, leading to inconsistent vector states and potential crashes. Additionally, a multithreading issue was identified, highlighting the importance of thread-safety mechanisms in code that can be accessed concurrently.

The Case of the Vector With an Impossibly Large Size

by Raymond Chen

From the article:

A customer had a program that crashed with this stack:

contoso!Widget::GetCost
contoso!StandardWidgets::get_TotalCost+0x12f
rpcrt4!Invoke+0x73
rpcrt4!Ndr64StubWorker+0xb9b
rpcrt4!NdrStubCall3+0xd7
combase!CStdStubBuffer_Invoke+0xdb
combase!ObjectMethodExceptionHandlingAction<<lambda_...> >+0x47
combase!DefaultStubInvoke+0x376
combase!ServerCall::ContextInvoke+0x6f3
combase!ComInvokeWithLockAndIPID+0xacb
combase!ThreadInvoke+0x103
rpcrt4!DispatchToStubInCNoAvrf+0x18
rpcrt4!RPC_INTERFACE::DispatchToStubWorker+0x1a9
rpcrt4!RPC_INTERFACE::DispatchToStubWithObject+0x1a7
rpcrt4!LRPC_SCALL::DispatchRequest+0x308
rpcrt4!LRPC_SCALL::HandleRequest+0xdcb
rpcrt4!LRPC_SASSOCIATION::HandleRequest+0x2c3
rpcrt4!LRPC_ADDRESS::HandleRequest+0x183
rpcrt4!LRPC_ADDRESS::ProcessIO+0x939
rpcrt4!LrpcIoComplete+0xff
ntdll!TppAlpcpExecuteCallback+0x14d
ntdll!TppWorkerThread+0x4b4
kernel32!BaseThreadInitThunk+0x18
ntdll!RtlUserThreadStart+0x21

They wondered if some recent change to Windows was the source of the problem, since it didn’t happen as much in earlier versions of Windows.

 

DR20 - The Equality Operator You Are Looking For -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGWe delve into how C++20 introduced changes to object comparisons, leading to unexpected behavior and the need for matching operator!= declarations.

DR20 - The Equality Operator You Are Looking For

by Sandor Dargo

From the article:

When I see DR, I immediately think about Disaster Recovery. That’s due to my first corporate job where I worked as a Database Administrator and we had regular exercises to simulate events when datacenters would be unavailable.

When you see DR in the title of a C++ proposal, it’s not about a disaster, it’s more about a bug. DR stands for defect report. But the paper itself is usually not about reporting that there is a problem - that has been already done -, but more about proposing a solution.

What’s more important is that defect reports are not becoming part of the latest standard, they retrospectively change the one that introduced the defect.

A defect of C++20’s equality operator

P2468R2 is addressing a problem that was introduced by C++20. C++20 brought us the spaceship operator (operator<=>), but it further changed the logic of object comparisons. It changed the meaning of == and != and how overload resolution applies to them.

Aggregates: C++17 vs. C++20 -- Andreas Fertig

Sometimes the small changes between two C++ standards really bite you. Today's post is about when I got bitten by a change to aggregates in C++20.

Aggregates: C++17 vs. C++20

by Andreas Fertig

From the article:

Attendees of my training classes usually assume that I know everything. I can say sorry, but that's not the case. One day in the past, I showed the following example during a class:

struct Point {
  int x;
  int y;
};

Point pt{2, 3};

The class did cover C++17 and C++20. The code of Point is a reduced version for this post. We were talking about C++17's structured bindings. I use Point to show the decomposition using C++ Insights.

I showed the behavior and certain variations while answering questions from the attendees. One question was about move and copy. The question leads me changing the initial code to the following one:


	
2
3
4
5
6
7
8
struct Point {
  int x;
  int y;

  Point(Point&&) = delete;  A 

};

Point pt{2, 3};
2
3
4
5
6
7
8
struct Point {
  int x;
  int y;

  Point(Point&&) = delete;  A 
};

Point pt{2, 3};
As you can see, in A, I deleted the move constructor. As far as I remember, this topic was more or less the last one for this day. Everything went well and as expected.

The next morning one of the attendees approached me with the question of why the code didn't compile on his machine. My usual answer here is that if C++ were be easy, I wouldn't have the job I have. Somehow this never shuts down such questions. I like curious attendees.

He shared his code via Compiler Explorer. Guess what? His code looked exactly like mine but didn't compile. Here is the error message from the compiler:

What are senders good for, anyway? -- Eric Niebler

In a recent blog post, Eric Niebler gets inside the soon-to-be-standard async programming model and shows why you should care.

What are senders good for, anyway?

by Eric Niebler

From the article:

At the heart of P2300 is a simple, elegant (IMHO) core that brings many benefits, but it’s hard to see that forest for all the trees.

So let’s make this concrete. In this post, I’ll show how to bring a crusty old C-style async API into the world of senders, and why you might want to do that.

How I Learned to Stop Worrying and Love Juggling C++ Atomics -- brilliantsugar

In his recent blog post brilliantsugar talks about technics to find race conditions in multithreading code by using different tools.

How I Learned to Stop Worrying and Love Juggling C++ Atomics

by brilliantsugar

From the blog post

As most C++ programmers are aware, courtesy of Herb Sutter, programming lock-free data structures is akin to juggling razor blades. Reasoning about concurrent programs is already complex enough but modern CPU memory models are so complicated that they manage to make it even harder. The prevailing suggestion you often come across is to steer clear of lock-free programming entirely.

In this article, I share the adventures of exploring methods for formally verifying lock-free C++ code. To showcase three different approaches, I delve into the implementation of a lock-free triple buffer data structure.

 

 

Class Invariants -- Andrzej Krzemieński

Andrzej talks in his recent blog post about class invariants.

Class Invariants

by Andrzej Krzemieński

About the blog post:

The primary motivation for defining a class in C++ is to reflect and maintain a class invariant. In this post we will see what class invariants are and how you deal with them. Class invariants are important part of C++, even though there is no “invariant” keyword in C++.