Building a better string class
For nearly thirty years I used a minimal C-with-classes style string class.
This started back in the early 1990s, when writing a block-mode terminal emulator for Windows (Win16). The standard C++ string class was not efficient, and this application did a lot of cyclic use of strings. I found that a minimal wrapper around standard C string functions, with a free list, radically more efficient.
After a bit more than a decade, revisited my old assumptions. Much had changed as applications were now on Win32 (then). CPUs and compilers had also advanced. But the standard C++ string class had not improved. My old choice was still valid.
Note the C++ applications I wrote back then were strictly single-threaded. There was simply not a need for multi-threading. (Keep in mind that almost all desktops and servers to that time had a only single CPU.)
A few years ago, had a notion for a thread-local lock-free string class. My first attempt had behavior I did not understand, and I lost interest.
Of late, I have been working through the LLM-programming learning curve, so asked an LLM to look at the prior attempt. Took a few iterations (filtering out the usual LLM noise) but ended up with measurements against a working string class.
Seems the standard C++ string class is now much more efficient. Not sure when exactly that happened, or why it took decades, but it is now time to revisit my old assumptions.
Seems I can still beat the standard C++ string class, least for my expected uses, but not by much.
The first column of numbers is for std::string and the second is for my base_strings::string_local_o class.
==== Using simple samples
std::string 6.959 ns : base_strings::string_local_o 6.792 ns pick
std::string 0.931 ns : base_strings::string_local_o 4.046 ns instantiate
std::string 31.820 ns : base_strings::string_local_o 16.097 ns assign from (const char*)
std::string 19.539 ns : base_strings::string_local_o 15.172 ns assign from same
std::string 7.219 ns : base_strings::string_local_o 2.781 ns dispose
==== Using sample bucket
std::string 6.930 ns : base_strings::string_local_o 6.177 ns pick
std::string 1.021 ns : base_strings::string_local_o 3.901 ns instantiate
std::string 29.588 ns : base_strings::string_local_o 18.542 ns assign from (const char*)
std::string 22.125 ns : base_strings::string_local_o 16.509 ns assign from same
std::string 8.112 ns : base_strings::string_local_o 2.804 ns dispose
This is not enough to suggest that anyone abandon std::string.
Source are on GitHub.
Disclaimer
If you are acquainted with the nature of error in measurement, you might correctly doubt the published precision. Measurement jitter means that rounding to 0.1 ns is not unreasonable. My only excuse is that at the start I did not know where the measures would land, and so output with excess precision.
I am certainly not claiming femtosecond accuracy. :)