C++11 introduced a ton of new features to ISO C++, admittedly already a very large language. Using C++ can often be surprising for many different reasons, but the most pleasant of surprises when using C++ is discovering a useful feature added in one of the recent specifications, or finding a (possibly additional) use for a feature you already knew about. I recently had such an experience with
At first glance, it doesn’t seem all that useful to have a “reference wrapper” as opposed to a plain old reference. Its immediate usefulness is obscured by the fact that it is only really useful when using other new features added with C++11 like
std::ref is a workaround for a case where template type deduction rules deduce a parameter type such that the parameter is taken by value, when the intention was to take the parameter by reference. Consider the following example, loosely based on the code I was working on:
Ignore the obvious design flaws here; this example is only meant to demonstrate what happens when you try and pass a value parameter by reference to a function being called from a templated function like
std::thread::thread(). Note that template type deduction is (correctly) deducing the type of value to be
int, but this doesn’t match the type
int& that it sees in start_thread. The actual error given by the compiler (in this case GCC) is actually much more obscure than that:
The compiler does show that the error is vaguely to do with binding the function parameters to the function passed in; a quick search online using keywords from the error pointed towards
std::ref as the solution.
So how does
std::ref solve the problem of passing parameters by reference into templated functions that have their parameter types deduced by value? The definition of
std::reference_wrapper (the type returned by
std::ref) and its libstdc++ documentation/source paint a pretty clear picture.
std::reference_wrapper is just a thin wrapper around a pointer that implicitly converts to a reference (through
operator T&() const):
So the deduced type of the parameter in the template function is
std::reference_wrapper<int> in the case of the example above), which can be passed into the function by value. This is the same size as a reference, and implicitly casts to one when it is passed to another function that expects one. So functionally, it smells and acts much like a reference. Let’s see it in action:
Great, no more messy template error messages, and everything works as expected.
To demonstrate the low overhead of this approach, I’ll use a slightly simpler example which uses
std::bind instead of
Here’s the key section of the assembly output, for the
With the optimization level set at
-O3 the assembly output is pretty tight. Compare that with the assembly after I remove the bind call and just call
print_value directly (the rest of the assembly is identical):
I’m no assembly expert, but I believe the difference is a function pointer referring to the print_value function and a result of the indirect function call (via
std::bind). It certainly seems to be true that
std::ref imposes no additional overhead to the function call by itself.
std::cref which I haven’t explicitly shown, but works in exactly the same way as
const& parameter types. If anything, I’ve used this more than the canonical
std::ref function. If you’re using C++03, you can still access this functionality via
boost::thread, boost::bind, etc.).
So there you have it!
std::cref have both become valuable tools in my C++11 and C++14 toolbox. Next time you reach for
std::thread or another C++ utility that performs a deferred function call internally, consider whether you should make use of