Posts

Showing posts from December, 2023

Clarifying functionality

Many conversions of loops to STL forms are near to net-zero in terms of complexity changes: From for (int i = 0: i != r.size(); ++i)     vec.emplace_back(r[i]); to for (auto iter = r.begin(): iter != r.end(); ++iter)     vec.emplace_back(*iter); to std::for_each (r.begin(), r.end(), [&vec](const auto& inVal) {     vec.emplace_back(inVal); }); to std::copy(r.begin(), r.end(), std::back_inserter(vec)); to std::ranges::copy(r, std::back_inserter(vec)); gives us five versions of the same operation in the same ballpark as far as figuring out what is going on, with only the last really giving us a noticeably shorter form because of the simpler form of the range algorithms.  (The last version is also almost certainly more efficient than the first version.) The biggest difference is that one can basically read the last one from left to right as "copy the contents of r onto the back of a vector vec". Some changes, though, can do a great deal to clarify ...

Revisiting the FileLineSource utility

A number of posts ago, I talked about a small utility called FileLineSource, which did a little bit of complexity hiding when reading lines from a text file. That utility had one implicit issue: it perpetuated the interface of std::getline(), for which it was, essentially, a drop-in replacement.  That meant that it was entirely functional, but it did not support the use of STL algorithms. Thus its use was something like this:   auto source = inFileFactory.create();   source->openSource();   std::string s;   while (source->getNextLine(s))     m_records.emplace_back(s); This could be improved upon.  It uses a C-style while loop, it's spread out over five lines, and it needs a bit of attention to see what it's doing. The way to address this was not to change the utility itself, but to add a wrapper.  Because the use for this corresponds to an input range, the simplest of ranges, we can provide a very simple wrapper which provides the missi...

Eliminating while

(This can be considered to be a meditation on one aspect of Sean Parent's "no raw loops" dictum.) The while loop is about as close to the bare metal as you can get while using structured programming idioms. It translates effortlessly into a test and a goto and in many cases the test is a couple of assembler instructions if the while loop is testing a location in memory (e.g. while(*cp++ == ' ')). If you need speed in a tight inner loop in a highly time-sensitive application, while is an excellent candidate. There are two other idiomatic uses of while() which are, as one might say, "worthwhile". The first is while(true) { ... } as an idiomatic way of marking an infinite loop which will be terminated only by a resource failure or program shutdown. (But see below for why this is not ideal when used to delimit a loop which can be terminated by an internal break statement - and this includes control loops for threads which have to terminate cleanly at exit.) ...