C++ Club - Meeting #126

Episode Date: April 1, 2021

For show notes, visit https://glebd.github.io/cppclub/CppClubUK-126-20210401.html...

Transcript
Discussion (0)
Starting point is 00:00:00 Meeting 126. Today is the 1st of April. The rest assured there won't be any jokes in the presentation. C++ is a serious matter. The March mailing is available. Many papers in flight, newer versions of papers we've seen before. The paper about renaming a std colony to std hive. They say it's bike shedding but I suspect that there are reasons behind the renaming. So some papers that caught my attention transactional memory light. I hadn't paid attention to it previously but now transactional memory proposal has become urgent, as they say, because this feature is now supported by hardware in commercial processors. The technical specification for transactional memory was approved in 2015, but it has not been widely implemented and used.
Starting point is 00:01:02 They say that there is interest in having some support for transactional memory even if it covers fewer use cases. Hence the light moniker for this paper. The idea is to support some important use cases with only a small addition to the language. And the addition to the language they propose is the atomic block. And the syntax would be atomic do and then calibrases block of code. The execution of code in an atomic block is called a transaction. Transactions are guaranteed to appear atomic with respect to other transactions. So transactions never form data races with other transactions.
Starting point is 00:01:46 However, there's no implied synchronization between transactions and non-transactional code. If you have a transactional code that accesses some memory and then unsynchronized non-transactional code accessing the same memory, writing to it, it results in undefined behavior. There are proposed syntactic alternatives to the language-level AtomicDo syntax construct. One of them is a lambda-based
Starting point is 00:02:13 execution framework. I suspect that would be library-level feature and it would look like std://tm__ex exec function that would get a lambda and execute it as a transaction presumably. The strengths advantages are no changes are required to the front end of the compiler and if you have a hardware support on such a system it could be implemented entirely as a library. Whereas without transactional memory support and hardware, it would still be possible to implement using mutexes. The third option is an RAI framework. Someone proposed to pronounce it as RAI. So this would introduce a transaction scope that you would create at the beginning of the scope, and then when the scope ends, it would end the transaction. The second one proposes a new syntax for deleting particular
Starting point is 00:03:13 template specializations. So we can delete functional loads, but for variable templates and class templates, deleting a particular instantiation specialization is not possible at the moment. So that's what this proposal is about. Here are some examples. Delete primary variable template allows specializations. You would say delete template type name int x equals delete, and then you would specialize it with a certain type that would only be
Starting point is 00:03:47 available. Same with deleting a particular variable specializations, and same with class templates. Delete primary allows specializations, and delete a particular specialization. The third one is version 5 of formatted output by Viktor Zverovich. He proposes a new IO-agnostic text formatting function. So in addition to the std format library that was added to C++20, he proposes a new function stdprint that would use the same syntax and would be an alternative to Iostreams. The proposed stdprint, he writes, improves usability, avoids locating a temporary stdstring object and calling operator output,
Starting point is 00:04:41 which performs formatted I.O. on text that is already formatted. So it's basically more efficient. The number of function calls is reduced to one, and with the type ratio results in much smaller binary code. The other big advantage of it would be built-in support for Unicode, because at the moment the terminal assumes code page 437, which means that any Unicode you output using standard streams turns into garbage. And lastly, the renaming of std colony to std hive. The name has too many meanings, meaning the colony, and the name is unfamiliar and not in common usage. Anyway, it's fine. The next one is balance functions in C++, an article about how good RAII is and how you should use it.
Starting point is 00:05:38 A balance function, the author says, is one of a pair of functions such as that every call to the first function must be balanced with exactly one call to the second function and vice versa. The canonical examples are malloc and free, others include open and close, lock unlock and start stop on connect disconnect. And the author says the best way to ensure balance function calls in C++ is by using constructors and destructors. In other words, RAI, as he calls it. So yeah, just a reminder and a good justification of using RAI, which surprisingly some C++ developers don't know about and don't use. It's baffling, really. Anyway, that's it about that i wonder what reddit says about this article oh yeah there is a good point if your class manages resources in this way you should delete the copy constructor and copy assignment operator i remember kate gregory did a presentation about
Starting point is 00:06:40 legacy code and working with legacy code bases one of the things she said was that on one project with one ancient codebase, the developers didn't know what RIAI was. We're very surprised and grateful to her for introducing it. There are still pockets in C++ community. Right, a series of performance-oriented articles by Scott Walchok. The first one C++ for performance trap number one, constant size std vector. So he basically talks about initialization of std vector in advance when you are initializing it dynamically. The usefulness of calling reserve if he goes through some generated code. An alternative would be to create
Starting point is 00:07:32 the vector with the size that you need. He only looks at the generated assembly and he says that in this case there's no capacity check and the inner loop gets unrolled. This is all with clang 11. It would also get vectorized, he says, if he didn't prohibit it explicitly. But there is an unnecessary call to memset near the start of the function. This is because the constructor guarantees that elements are default constructed. We can't create a vector of uninitialized space even though we know that we're about to initialize the whole vector. An alternative that he uses to demonstrate the point is to explicitly allocate memory and put the objects there without using a vector. It results in shorter assembly, doesn't contain an initial call to
Starting point is 00:08:26 memset obviously, and the inner loop is very similar. Of course you can use std array for that when you know the maximum size and then everything is perfect. Rust gets a mention. He translated examples to Rust and the contrast he says was quite interesting. Rust. And the contrast, he says, was quite interesting. Rust has vec with capacity, which is more convenient than calling vec new followed by reserve. You can apparently create an initialized box of memory heap allocated array, but it requires the latest version of Rust, unreleased yet, and add safe code.
Starting point is 00:09:03 So that's not idiomatic Rust apparently, so he didn't do it. The compiler didn't unroll the loop because it wasn't able to remove the bounce checks, so yeah, Rust is safe, but in this case it's slower. There is a link to more software optimization resources, some pdf files that might be useful. Optimizing software in C++, an optimization guide for Windows, Linux and Mac platforms. I think it was from the reddit thread, this link. This one says, as mentioned in the article, std vector is widely promoted as a great default container, but it's pretty obvious that that doesn't extend to constant size vectors
Starting point is 00:09:45 that's what std arrays for and don't use c style arrays the boost container library has a static vector template which is a variable size array container with fixed capacity the next one is unnecessary std function i believe we've mentioned this before, the overhead of std function. Scott says the drawbacks of it are it is fairly large, 32 bytes on a 64-bit system, and it causes type info for each used lambda to be generated. So interestingly, he wants to clear up one possible misconception. The type of a lambda object is not std function. Instead, it has unique unnamed non-union, non-aggregate class type known as closure type. So this is the contrasting implementation without
Starting point is 00:10:34 std function, but just using a template and calling whatever is passed to the function. In this case, the whole thing is just a simple call to printf and a tail call to call function since we marked it in the known line. He says of course std function serves a purpose and we can't just always use the template technique if we wanted to store the function for later use as a callback. Currently std function might be our most reasonable choice. But there are some proposals in flight as I remember to introduce better alternatives, more efficient ones.
Starting point is 00:11:05 Another article by Scott is about inlining and compiler optimizations. Inlining, he says, enables other compiler optimizations. In this article, he shows examples of constant propagation and loop invariant code motion. Constant propagation turns references to variables whose value is known into uses of those constant values instead. For example, instead of a load from a memory location, the compiler may generate a use of an immediate value. He talks about generated assembly and says that print is loading from memory because nonconst num here above is not const. Some other file in the program may declare extern int nonconst num and mutate it.
Starting point is 00:11:52 But every other example is using a mov with an immediate value to set the argument to print num because the compiler can see that the values are constants. And the loop invariant code motion moves expressions that are constant across iterations of a loop outside the loop. This is sometimes referred to as hoisting code. I haven't heard that. Because the code is moved above the loop body. Compilers are smart. I remember when in code reviews many years ago this kind of thing would be flagged if you sort of used some constant inside the loop and you had to move it outside manually, but these days looks like compilers can perfectly well do it all by themselves. Next is a library called CLI, which is a cross-platform header-only C++14
Starting point is 00:12:40 library for interactive command line interfaces, Cisco style, whatever that means. I haven't used that, but I can see how this could be very useful. Like if you know that your command line program has to be interactive and not just accept command line arguments, you might want to implement something like this. It supports menus and submenus, auto-completion, persistent history, async interface and colors. No dependencies except ASIO, only to provide Telnet server.
Starting point is 00:13:17 So it supports both Linux and Windows. There's a whole interpreter for command line and it's an asynchronous library. And the handlers of commands are executed by a scheduler. That's quite sophisticated for a header-only library. It's licensed using Boost Software License. By the way, I heard that the Boost Software License is better than MIT because of some issues with contributing code. So Boost takes care of contributors and their contributions better than the MIT license. This is an introduction to using Lua with C++ with Sol2. If you remember, Sol2 is a Lua integration library by Jean-Hyd Menid.
Starting point is 00:13:59 And Hristo Stamenov writes his own experiences of using that. In this case, as probably in most cases, it's a game that makes use of Lua for game logic. He just goes and explains how to use raw Lua code in C++. You can have a block of Lua code and then interpret it using Sol2, which could be really useful if you wanted to easily modify game-related variables and logic. This is an error in a recent version of a book that someone noticed on Reddit. The book is Professional C++ by Mark Gregoire, and this is the quote. Statements of the form return object trigger return value optimization, RVO.
Starting point is 00:14:46 If object is a local variable, a parameter to function or a temporary value. So someone pointed out that it doesn't work with a parameter to the function and provided a link to the copy lesion explanation on CPP reference. This just goes to show that books have errors in them sometimes. This is not strictly C++ related, but it's a nice resource and I thought I'd include it. Microsoft provides free Windows 10 development virtual machines for Hyper-V, Parallels, VirtualBox and VMware. Scott Hanselman of Microsoft writes it on his blog and provides links to virtual machine downloads at Microsoft.
Starting point is 00:15:29 These are time limited, I believe to 60 days, but it being a virtual machine, if you haven't finished your development, you can just download a new one. And there are also free developer tools for Windows 10. That includes Visual Studio Community Edition, which is completely free, and Visual Studio Professional and Enterprise with 60 or maybe 30 days trials. There are lots of other interesting tools. Most popular of those is probably Visual Studio Code. Another theme for Doxygen. This one's a particularly nice looking and non-intrusive. Installing it means just pointing your Doxy file to a custom CSS file. It produces a very nice and modern looking documentation for your code without any other changes. Speaking of documentation, H-Doc is an Adobe C++ documentation tool,
Starting point is 00:16:26 and they've open-sourced it. So it's now on GitHub. It's written in C++ mostly. And see, there's nice documentation for it. Interestingly, it seems to use Misson build system. This is a C++ blog role. The site blogserve.io is a blog aggregator that can assemble blogs by a tag. And these are the blogs tagged CPP. So all of the most popular and known blogs are here.
Starting point is 00:16:57 But since it's dynamic, it's useful to have it as a bookmark in case new blogs appear. And some of them I haven't seen so that's for the bookmarks. There is a corresponding Reddit thread with some more blog links. Another library concurrent deck and thief pool. Concurrent deck is a lock-free concurrent queue. The guy received lots of feedback but generally it seems like a useful library implementing the chase-leve technique. There's a link to that paper.
Starting point is 00:17:30 And afterwards, the same author implemented a thread pool based on that cue. It's called Thief Pool, a blazing fast, lightweight, work-stealing thread pool for C++20. It's built on a lock-free concurrent Riften deck. What is work-stealing thread pool for C++20. It's built on a lock-free concurrent Riften deck. What is work-stealing thread pool? There is no explanation. And the author says it's a thread pool where each thread has its own work queue. They then steal other threads' work when they run out. This removes the single queue bottleneck.
Starting point is 00:18:01 Alia, a library for interactive applications. It's not a GUI as I thought initially. Instead it's a web interface library. It's currently targeting HTML5 and the web. So if you want to write your web applications in C++ and use that silly node or not JavaScript or TypeScript or whatever. You can totally do it. Well, this is kind of a roundabout way. You program in C++, it results in a web page, which then gets interpreted by JavaScript that's written in C++. There's a bootstrap-based bootstrap. It's sort of a CSS HTML application framework.
Starting point is 00:18:47 So there are HTML bindings to it. Bartok Filipek talks here about constexpr dynamic memory allocation on his CPP Stories blog. So constexpr, he says, evolved into almost another sub-language, an alternative to regular template code. And in C++20, you can even use std vector and std string in constexpr context. And here he says, he explains that now it's possible to use memory allocations in a constexpr context. The main topic to understand, he says, is transient allocation. It means that you can allocate memory in a constexpr expression, but then the mem block must be released at the end of that expression. This way the compiler can adequately track all the allocations and it's much easier to control and implement. The limitations
Starting point is 00:19:34 are the memory allocation cannot go outside the constant expression and thus you cannot use it, for example, to create lookup tables. And one trick to overcome that, he says, would be to somehow copy the result into a std array. A useful new feature. We've seen Connor Hextra's presentations before about choosing the right algorithm for the job. And on his blog, he has a sort of meta algorithm of selecting the best algorithm for the job. There's a table that he updated recently. And I think it's another one for the bookmarks. His advice is always choose the most specialized algorithm.
Starting point is 00:20:17 And the diagram, this diagram is for find if, any of, and std mismatch algorithms. Links between them. And there is an update. He says, STL pointed out that is-partitioned-until and is-partitioned could be added to the diagram. They can be thought of as weaker versions of is-sorted. So yeah, a very useful website and a diagram. Okay, so that's it for today. I'll leave you with this tweet. Software is never finished, merely abandoned. Thank you all for coming, and I'll talk to you next week.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.