Modern C++, iterators and loops compared to C#

It has been a while since I looked much at modern C++. I’ve started intentionally simple and was exploring some of the ways that a simple list can be iterated. I hate to say this, but I remember the days when the standard template library was not necessarily something that was the easiest to get working on Windows with a Microsoft C++ compiler in a simple, safe and reliable way. My, how times have changed for the better!

While the overall syntax of C++ lacks the refined and designed elegance of a C# application, it has come a very long way!

I’ve thrown together a simple sample. The code creates a list of strings, pushes (not add, arrgh!) strings onto the list, and then iterates through the list in three similar, but syntactically different methods below:

image

OK, there’s a few awesome things here that make C++ much more approachable these days:

  1. a decent string class! No more hunting for a library or header file that has most of the functionality you need. (there’s a wstring as well for wchar_t needs)
  2. All the common Data structure types like list, map, vector, etc… that you might need without writing them your self.
  3. With using, the code doesn’t need to refer to types with namespaces (much like C#). So, instead of std::list<std:string>, it’s just list<string>, which I consider far more readable at a glance.
  4. No weird casting or worrying about strings when values are passed to the push_back function. Again, it just works.
  5. auto – the var of C# is called auto in C++. If I hadn’t used auto in the first iterator, the code would have declared the type as list<string>::iterator. While not terrible, auto reads well, as it’s likely that I’ll not need the detailed declaration to understand what’s being iterated upon.
  6. Second option is just syntactical sugar as it internally uses a standard for loop like in the first example internally. But, you’ll note there are anonymous functions/lambdas! The square [] brackets is the capture clause of the lambda expression. Unlike C#, where the compiler automatically determines what outer scoped variables will be used by the inner lambda function, in C++, it’s necessary to explicitly declare what is required. While this is a bit annoying, there are times where this extra declaration might cause programmers to think twice about all of the variables that are required in the lambda expression. In this instance, there aren’t any variables needed, so it’s empty.
  7. The last example is the most concise, and maybe a little less friendly at first and that’s mostly due to the heritage of C++ and how to make code most efficient. It’s called a range-based for statement. First, the code is using auto again and the type is a string as it’s declaring the type used within the list. The & symbol remember is a reference and the const is indicating that the value will not be changed by the inner block. These two together ideally make it so the value is observed in-place, without any need for a copy.

While the range-based for statement isn’t quite as readable as C#:

image

I think you might agree that the C++ version is more than passable, and nearly friendly!

image

(Aside, there is a shortcut initializer list syntax that can be used with non-aggregate types in C++, so an int for example that would have gotten rid of the calls to push_back).