When faced with passing multiple options as arguments to functions, C++ programmers will use
enum class without much hesitation. Since C+11, it feels like we have moved away from magic numbers and magic string values, and in most cases, it’s for the best. There seems to be one exception: when we only have two options to choose from.
Here, I will try to convince you to stop overusing bools that don’t convey true/false or yes/no.
For making interfaces safer, more expressive, and nicer to use, I will advocate for the following rule of thumb:
If you read out the function…
In a previous article, I showed how Rust prevents us from introducing race conditions and invalid memory access to our code in multi-threaded contexts. In this article, we will look at several kinds of memory access bugs in single-threaded C++ and how Rust prevents us from making these mistakes.
Returning references to temporaries causes the callers of our functions to access invalid memory, and either crash their application or worse, overwrite random memory and cause a hard to debug error later. References can also be hidden inside classes we may return, whether they’re our own or from the standard library.
In most low-level programming languages, we are used to describing how what we want is achieved, rather that what we want to achieve in the first place. In some cases, this imperative approach outperforms any other approaches in time and memory complexity.
There exist cases, however, where we are able to write declarative statements that are just as effective as their imperative counterparts, while being much easier to read and easier to change and maintain. In this article, I would like to highlight three declarative use-cases that Rust excels in.
For value-oriented programming languages, move semantics present a big step forward in both optimization and representing uniqueness invariants. C++ has chosen the path of non-destructive moves, where moved-from variables are still usable (albeit usually in an unspecified state). Rust, on the other hand, uses destructive moves, where the moved-from variable can no longer be used. I’ll introduce both approaches in a little more detail and present some issues with non-destructive moves. Finally, I will present what C++ could have looked like with destructive moves.
In C++, each expression has not only a type, but also a value category. There exist…
Multithreading is hard. C++ is hard too. I will demonstrate how we can make multithreading at least a little easier by avoiding some of the pitfalls in C++ by using Rust instead.
Some of the C++ examples listed here are modified versions of examples from Top 20 C++ multithreading mistakes and how to avoid them by Deb Haidar, others I made up myself.
Keep in mind that all of the examples listed here are toy examples: in real-world codebases, multithreading is usually much more complicated than this, and preventing these mistakes in C++ may be that much more difficult. …