When C++11 introduced auto
, it opened up a whole range of useful techniques and improved the life of C++ developers in a variety of ways. There’s no shortage of simple examples and tutorials teaching how to start using auto
, but as is often the case, many of these well intentioned examples have left readers with an incomplete picture of how to use auto
effectively and in some cases have resulted in poor habits becoming common practice. Since auto
essentially hides away some of the details of how objects are created, there is a risk that developers don’t think as carefully about what is actually taking place. This article aims to arm the reader with information often omitted so that common pitfalls can be avoided.
C++11
Includes topics and techniques specifically related to features added in C++11.
Member Function Overloading: Choices You Didn’t Know You Had
Let’s explore your understanding of member function overloading. For a given class, how many different non-template overloads can you define for a given function where the function takes no arguments? Putting aside exception specifications (since allowing them would make the answer to this essentially infinite), let’s make this a multiple choice, pick your answer from: 1, 2, 4 or 8. I’ll even provide a clue that the return types of the functions don’t matter. For extra points, how many of the function overloads are likely to be useful?
Move constructors can copy and std::move doesn’t move anything
I recently came across an interesting use of std::move
which looked something like the following:
void MyObject::processItems()
{
std::vector<int> items(std::move(m_items));
for (auto item : items)
{
// Do things which may add new items to m_items
}
}
The intent of the code was that every time the member function processItems()
was called, it would perform some operation on each item held in the member variable m_items
. Each processed item should be removed from m_items
. The operation to be performed might generate new items which would be added to m_items
, so care had to be taken about how to iterate over the set of items.
To ensure robust iteration over the items to be processed, the code transfers the contents of m_items
to a local object and then iterates over that local object. Thus, if new items are created during processing, they would be added to m_items
and the container being iterated over (items
) would not be affected. All good, right? Well, probably yes, but by no means is it guaranteed.
OnLeavingScope: The sequel
In a previous article, the OnLeavingScope
class was presented as a technique for robustly and concisely handling scenarios involving multi-step setup, run and cleanup stages. It focused on ease of learning and wide applicability rather than performance, so while the implementation was complete, it was not necessarily optimal. This article picks up where the previous article left off and deals with some of the more advanced aspects to provide some improvements.
Let your compiler do your housekeeping
A common sequence of steps we mortal software developers frequently find ourselves implementing goes something like this:
- Perform some sort of setup or acquire some sort of resource.
- Carry out some arbitrary sequence of actions.
- Tear down things we setup or release resources we acquired in step 1.
There are well-known patterns for implementing this scenario robustly, but when there are multiple sub-steps to be performed in the setup phase and where any of those sub-steps can each fail individually, things get more complicated. This article presents a concise, self-documenting and robust way to handle these more complicated cases. A follow-up article will extend this further to improve some performance characteristics and ends up having a lot in common with the ScopeGuard11
pattern described in various places online.
The multi-step setup problem
Conceptually, the problem we want to solve can be described as follows:
- For each setup sub-step:
- Perform sub-step.
- If sub-step fails, stop and release/clean up after all previous setup sub-steps.
- Carry out some arbitrary sequence of actions.
- Tear down things we setup or release resources we acquired in all sub-steps of step 1.
Enabling C++11 And Later In CMake
Updated June 2020
With the constant evolution of C++, build systems have had to deal with the complication of selecting the relevant compiler and linker flags. If your project targets multiple platforms and compilers, this can be a headache to set up. Happily, with features added in CMake 3.1, it is trivial to handle this in a generic way.
Practical uses for variadic templates
You might not have even heard of parameter packs or variadic templates before, but if you’ve worked with C++ templates for a while, chances are at some point you’ve wanted the functionality they provide. This post provides a few practical examples showing some of the problems they solve and techniques they enable.
Lambdas for lunch
Alright, so lambdas in C++ are cool and we’ve been coding with one arm tied behind our back all this time. C++11 brought us this wonderful goodness, which is great, but just how do you actually use them? No messing around, let’s jump right in!
Iterating over an enum
The enum
feature of C/C++ is far from new. It is very useful for defining a specific set of values that a simple integer may take, which can lead to clearer, more concise code when used appropriately. Many compilers are capable of warning about common errors associated with enum
use, such as not including case
statements for all possible enum
values in a switch
statement that has no default
clause. In many respects, an enum
acts like a set, but being essentially just a glorified int
, it lacks any of the container features of something like std::set
.
The developer typically faces a tradeoff between performance and functionality when deciding between an enum
or some kind of set-like container. There are some (often common) situations, however, where an enum
can still be treated like a container, thanks to features made available in C++11.
C++ list initialization
Containers
Consider this very typical piece of C/C++ code for creating an array of integers from a list of specified values (called a braced initializer):
const int[] someInts = {23, 10, 5, 17};
This is simple and works well where a plain int
array is needed, but sometimes we want to do something similar with STL containers.