In this chapter we will cover:
Getting configuration options
Storing any value in a container/variable
Storing multiple chosen types in a container/variable
Using a safer way to work with a container that stores multiple chosen types
Returning a value or flag where there is no value
Returning an array from a function
Combining multiple values into one
Reordering the parameters of a function
Binding a value as a function parameter
Using the C++11 move emulation
Making a noncopyable class
Making a noncopyable but movable class
Boost is a collection of C++ libraries. Each library has been reviewed by many professional programmers before being accepted to Boost. Libraries are tested on multiple platforms using many compilers and the C++ standard library implementations. While using Boost, you can be sure that you are using one of the most portable, fast, and reliable solutions that is distributed under a license suitable for commercial and open source projects.
Many parts of Boost have been included in C++11, and even more parts are going to be included in the next standard of C++. You will find C++11-specific notes in each recipe of this book.
Without a long introduction, let's get started!
In this chapter we will see some recipes for everyday use. We'll see how to get configuration options from different sources and what can be cooked up using some of the datatypes introduced by Boost library authors.
Take a look at some of the console programs, such as cp
in Linux. They all have a fancy help, their input parameters do not depend on any position, and have a human readable syntax, for example:
$ cp --help Usage: cp [OPTION]... [-T] SOURCE DEST -a, --archive same as -dR --preserve=all -b like --backup but does not accept an argument
You can implement the same functionality for your program in 10 minutes. And all you need is the
Boost.ProgramOptions
library.
Basic knowledge of C++ is all you need for this recipe. Remember that this library is not a header-only, so your program will need to link against the libboost_program_options
library.
Let's start with a simple program that accepts the number of apples and oranges as input and counts the total number of fruits. We want to achieve the following result:
$ our_program –apples=10 –oranges=20 Fruits count: 30
Perform the following steps:
First of all, we need to include the
program_options
header and make an alias for theboost::program_options
namespace (it is too long to type it!). We would also need an<iostream>
header:#include <boost/program_options.hpp> #include <iostream> namespace opt = boost::program_options;
Now we are ready to describe our options:
// Constructing an options describing variable and giving // it a textual description "All options" to it. opt::options_description desc("All options"); // When we are adding options, first parameter is a name // to be used in command line. Second parameter is a type // of that option, wrapped in value<> class. // Third parameter must be a short description of that // option desc.add_options() ("apples", opt::value<int>(), "how many apples do you have") ("oranges", opt::value<int>(), "how many oranges do you have") ;
We'll see how to use a third parameter a little bit later, after which we'll deal with parsing the command line and outputting the result:
// Variable to store our command line arguments opt::variables_map vm; // Parsing and storing arguments opt::store(opt::parse_command_line(argc, argv, desc), vm); opt::notify(vm); std::cout << "Fruits count: " << vm["apples"].as<int>() + vm["oranges"].as<int>() << std::endl;
That was simple, wasn't it?
Let's add the
--help
parameter to our option's description:("help", "produce help message")
Now add the following lines after
opt::notify(vm);
, and you'll get a fully functional help for your program:if (vm.count("help")) { std::cout << desc << "\n"; return 1; }
Now, if we call our program with the
--help
parameter, we'll get the following output:All options: --apples arg how many apples do you have --oranges arg how many oranges do you have --help produce help message
As you can see, we do not provide a type for the option's value, because we do not expect any values to be passed to it.
Once we have got through all the basics, let's add short names for some of the options, set the default value for apples, add some string input, and get the missing options from the configuration file:
#include <boost/program_options.hpp> // 'reading_file' exception class is declared in errors.hpp #include <boost/program_options/errors.hpp> #include <iostream> namespace opt = boost::program_options; int main(int argc, char *argv[]) { opt::options_description desc("All options"); // 'a' and 'o' are short option names for apples and // oranges 'name' option is not marked with // 'required()', so user may not support it desc.add_options() ("apples,a", opt::value<int>()->default_value(10), "apples that you have") ("oranges,o", opt::value<int>(), "oranges that you have") ("name", opt::value<std::string>(), "your name") ("help", "produce help message") ; opt::variables_map vm; // Parsing command line options and storing values to 'vm' opt::store(opt::parse_command_line(argc, argv, desc), vm); // We can also parse environment variables using // 'parse_environment' method opt::notify(vm); if (vm.count("help")) { std::cout << desc << "\n"; return 1; } // Adding missing options from "aples_oranges.cfg" // config file. // You can also provide an istreamable object as a // first parameter for 'parse_config_file' // 'char' template parameter will be passed to // underlying std::basic_istream object try { opt::store( opt::parse_config_file<char>("apples_oranges.cfg", desc), vm ); } catch (const opt::reading_file& e) { std::cout << "Failed to open file 'apples_oranges.cfg': " << e.what(); } opt::notify(vm); if (vm.count("name")) { std::cout << "Hi," << vm["name"].as<std::string>() << "!\n"; } std::cout << "Fruits count: " << vm["apples"].as<int>() + vm["oranges"].as<int>() << std::endl; return 0; }
This example is pretty trivial to understand from code and comments. Much more interesting is what output we get on execution:
$ ./our_program --help All options: -a [ --apples ] arg (=10) how many apples do you have -o [ --oranges ] arg how many oranges do you have --name arg your name --help produce help message $ ./our_program Fruits count: 30 $ ./our_program -a 10 -o 10 --name="Reader" Hi,Reader! Fruits count: 20
The C++11 standard adopted many Boost libraries; however, you won't find Boost.ProgramOptions
in it.
Boost's official documentation contains many more examples and shows more advanced features of
Boost.ProgramOptions
, such as position-dependent options, nonconventional syntax, and more. This is available at the following link:http://www.boost.org/doc/libs/1_53_0/doc/html/program_options.html
Tip
Downloading the example code
You can download the example code files for all Packt books that you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the files e-mailed directly to you.
If you have been programming in Java, C#, or Delphi, you will definitely miss the ability to create containers with the Object
value type in C++. The Object
class in those languages is a basic class for almost all types, so you are able to assign (almost) any value to it at any time. Just imagine how great it would be to have such a feature in C++:
#include <iostream> #include <vector> #include <string> #include <auto_ptr.h> int main() { typedef std::auto_ptr<Object> object_ptr; std::vector<object_ptr> some_values; some_values.push_back(new Object(10)); some_values.push_back(new Object("Hello there")); some_values.push_back(new Object(std::string("Wow!"))); std::string* p = dynamic_cast<std::string*>(some_values.back().get()); assert(p); (*p) += " That is great!\n"; std::cout << *p; return 0; }
We'll be working with the header-only library. Basic knowledge of C++ is all you need for this recipe.
In such cases, Boost offers a solution, the Boost.Any
library, which has an even better syntax:
#include <boost/any.hpp> #include <iostream> #include <vector> #include <string> int main() { std::vector<boost::any> some_values; some_values.push_back(10); const char* c_str = "Hello there!"; some_values.push_back(c_str); some_values.push_back(std::string("Wow!")); std::string& s = boost::any_cast<std::string&>(some_values.back()); s += " That is great!\n"; std::cout << s; return 0; }
Great, isn't it? By the way, it has an empty state, which could be checked using the empty()
member function (just as in STL containers).
You can get the value from boost::any
using two approaches:
boost::any variable(std::string("Hello world!")); //#1: Following method may throw a boost::bad_any_cast exception // if actual value in variable is not a std::string std::string s1 = boost::any_cast<std::string>(variable); //#2: If actual value in variable is not a std::string // will return an NULL pointer std::string* s2 = boost::any_cast<std::string>(&variable);
The boost::any
class just stores any value in it. To achieve this it uses the type erasure technique (close to what Java or C# does with all of its types). To use this library, you do not really need to know its internal implementation, so let's just have a quick glance at the type erasure technique. Boost.Any
, on assignment of some variable of type T
, constructs a type (let's call it holder<T>
) that may store a value of the specified type T
, and is derived from some internal base-type placeholder. A placeholder has virtual functions for getting std::type_info
of a stored type and for cloning a stored type. When any_cast<T>()
is used, boost::any
checks that std::type_info
of a stored value is equal to typeid(T)
(the overloaded placeholder's function is used for getting std::type_info
).
Such flexibility never comes without a cost. Copy constructing, value constructing, copy assigning, and assigning values to instances of boost::any
will call a dynamic memory allocation function; all of the type casts need to get runtime type information (RTTI); boost::any
uses virtual functions a lot. If you are keen on performance, see the next recipe, which will give you an idea of how to achieve almost the same results without dynamic allocations and RTTI usage.
Another disadvantage of Boost.Any
is that it cannot be used with RTTI disabled. There is a possibility to make this library usable even with RTTI disabled, but it is not currently implemented.
Boost's official documentation may give you some more examples, and it can be found at http://www.boost.org/doc/libs/1_53_0/doc/html/any.html
The Using a safer way to work with a container that stores multiple chosen types recipe for more info on the topic
Are you aware of the concept of unrestricted unions in C++11? Let me tell you about it in short. C++03 unions can only hold extremely simple types of data called POD (plain old data). So in C++03, you cannot, for example, store std::string
or std::vector
in a union. C++11 relaxes this requirement, but you'll have to manage the construction and destruction of such types by yourself, call in-place construction/destruction, and remember what type is stored in a union. A huge amount of work, isn't it?
We'll be working with the header-only library, which is simple to use. Basic knowledge of C++ is all you need for this recipe.
Let me introduce the Boost.Variant
library to you.
The
Boost.Variant
library can store any of the types specified at compile time; it also manages in-place construction/destruction and doesn't even require the C++11 standard:#include <boost/variant.hpp> #include <iostream> #include <vector> #include <string> int main() { typedef boost::variant<int, const char*, std::string> my_var_t; std::vector<my_var_t> some_values; some_values.push_back(10); some_values.push_back("Hello there!"); some_values.push_back(std::string("Wow!")); std::string& s = boost::get<std::string>(some_values.back()); s += " That is great!\n"; std::cout << s; return 0; }
Great, isn't it?
Boost.Variant
has no empty state, but has anempty()
function, which always returnsfalse
. If you do need to represent an empty state, just add some trivial type at the first position of the types supported by theBoost.Variant
library. WhenBoost.Variant
contains that type, interpret it as an empty state. Here is an example in which we will use aboost::blank
type to represent an empty state:typedef boost::variant<boost::blank, int, const char*, std::string> my_var_t; // Default constructor will construct an // instance of boost::blank my_var_t var; // 'which()' method returns an index of a type, // currently held by variant. assert(var.which() == 0); // Empty state var = "Hello, dear reader"; assert(var.which() != 0);
You can get a value from a variant using two approaches:
boost::variant<int, std::string> variable(0); // Following method may throw a boost::bad_get // exception if actual value in variable is not an int int s1 = boost::get<int>(variable); // If actual value in variable is not an int // will return an NULL pointer int* s2 = boost::get<int>(&variable);
The boost::variant
class holds an array of characters and stores values in that array. Size of the array is determined at compile time using sizeof()
and functions to get alignment. On assignment or construction of boost::variant
, the previous values are in-place destroyed, and new values are constructed on top of the character array using the new placement.
The Boost.Variant
variables usually do not allocate memory in a heap, and they do not require RTTI to be enabled. Boost.Variant
is extremely fast and used widely by other Boost libraries. To achieve maximum performance, make sure that there is a trivial type in the list of supported types, and that this type is at the first position.
Imagine that you are creating a wrapper around some SQL database interface. You decided that boost::any
will perfectly match the requirements for a single cell of the database table. Some other programmer will be using your classes, and his task would be to get a row from the database and count the sum of the arithmetic types in a row.
Here's how the code would look:
#include <boost/any.hpp> #include <vector> #include <string> #include <typeinfo> #include <algorithm> #include <iostream> // This typedefs and methods will be in our header, // that wraps around native SQL interface typedef boost::any cell_t; typedef std::vector<cell_t> db_row_t; // This is just an example, no actual work with database. db_row_t get_row(const char* /*query*/) { // In real application 'query' parameter shall have a 'const // char*' or 'const std::string&' type? See recipe Using a // reference to string type in Chapter 7, Manipulating Strings // for an answer. db_row_t row; row.push_back(10); row.push_back(10.1f); row.push_back(std::string("hello again")); return row; } // This is how a user will use your classes struct db_sum: public std::unary_function<boost::any, void> { private: double& sum_; public: explicit db_sum(double& sum) : sum_(sum) {} void operator()(const cell_t& value) { const std::type_info& ti = value.type(); if (ti == typeid(int)) { sum_ += boost::any_cast<int>(value); } else if (ti == typeid(float)) { sum_ += boost::any_cast<float>(value); } } }; int main() { db_row_t row = get_row("Query: Give me some row, please."); double res = 0.0; std::for_each(row.begin(), row.end(), db_sum(res)); std::cout << "Sum of arithmetic types in database row is: " << res << std::endl; return 0; }
If you compile and run this example, it will output a correct answer:
Sum of arithmetic types in database row is: 20.1
Do you remember what your thoughts were when reading the implementation of operator()
? I guess they were, "And what about double, long, short, unsigned, and other types?". The same thoughts will come to the mind of a programmer who will use your interface. So you'll need to carefully document values stored by your cell_t
, or read the more elegant solution described in the following sections.
Reading the previous two recipes is highly recommended if you are not already familiar with the Boost.Variant
and Boost.Any
libraries.
The Boost.Variant
library implements a visitor programming pattern for accessing the stored data, which is much safer than getting values via boost::get<>
. This pattern forces the programmer to take care of each variant type, otherwise the code will fail to compile. You can use this pattern via the boost::apply_visitor
function, which takes a visitor functional object as the first parameter and a variant as the second parameter. Visitor functional objects must derive from the boost::static_visitor<T>
class, where T
is a type being returned by a visitor. A visitor object must have overloads of operator()
for each type stored by a variant.
Let's change the cell_t
type to boost::variant<int, float, string>
and modify our example:
#include <boost/variant.hpp> #include <vector> #include <string> #include <iostream> // This typedefs and methods will be in header, // that wraps around native SQL interface. typedef boost::variant<int, float, std::string> cell_t; typedef std::vector<cell_t> db_row_t; // This is just an example, no actual work with database. db_row_t get_row(const char* /*query*/) { // See the recipe "Using a reference to string type" // in Chapter 7, Manipulating Strings // for a better type for 'query' parameter. db_row_t row; row.push_back(10); row.push_back(10.1f); row.push_back("hello again"); return row; } // This is how code required to sum values // We can provide no template parameter // to boost::static_visitor<> if our visitor returns nothing. struct db_sum_visitor: public boost::static_visitor<double> { double operator()(int value) const { return value; } double operator()(float value) const { return value; } double operator()(const std::string& /*value*/) const { return 0.0; } }; int main() { db_row_t row = get_row("Query: Give me some row, please."); double res = 0.0; db_row_t::const_iterator it = row.begin(), end = row.end(); for (; it != end; ++it) { res += boost::apply_visitor(db_sum_visitor(), *it); } std::cout << "Sum of arithmetic types in database row is: " << res << std::endl; return 0; }
The Boost.Variant
library will generate a big switch
statement at compile time, each case of which
will call a visitor for a single type from the variant's list of types. At runtime, the index of the stored type can be retrieved using which()
, and a jump to the correct case in the switch will be made. Something like this will be generated for boost::variant<int, float, std::string>
:
switch (which()) { case 0: return visitor(*reinterpret_cast<int*>(address())); case 1: return visitor(*reinterpret_cast<float*>(address())); case 2: return visitor(*reinterpret_cast<std::string*>(address())); default: assert(false); }
Here, the address()
function returns a pointer to the internal storage of boost::variant<int, float, std::string>
.
If we compare this example with the first example in this recipe, we'll see the following advantages of boost::variant
:
We know what types a variable can store
If a library writer of the SQL interface adds or modifies a type held by a variant, we'll get a compile-time error instead of incorrect behavior
After reading some recipes from Chapter 4, Compile-time Tricks, you'll be able to make the visitor object so generic that it will be able to work correctly even if the underlying types change
Boost's official documentation contains more examples and a description of some other features of
Boost.Variant
, and is available at the following link:
Imagine that we have a function that does not throw an exception and returns a value or indicates that an error has occurred. In Java or C# programming languages, such cases are handled by comparing a return value from a function value with a null pointer; if it is null then an error has occurred. In C++, returning a pointer from a function confuses library users and usually requires dynamic memory allocation (which is slow).
Ladies and gentlemen, let me introduce you to the Boost.Optional
library using the following example:
The try_lock_device()
function tries to acquire a lock for a device, and may succeed or not depending on different conditions (in our example it depends on the rand()
function call). The function returns an optional variable that can be converted to a Boolean variable. If the returned value is equal to Boolean true
, then the lock is acquired, and an instance of a class to work with the device can be obtained by dereferencing the returned optional variable:
#include <boost/optional.hpp> #include <iostream> #include <stdlib.h> class locked_device { explicit locked_device(const char* /*param*/) { // We have unique access to device std::cout << "Device is locked\n"; } public: ~locked_device () { // Releasing device lock } void use() { std::cout << "Success!\n"; } static boost::optional<locked_device> try_lock_device() { if (rand()%2) { // Failed to lock device return boost::none; } // Success! return locked_device("device name"); } }; int main() { // Boost has a library called Random. If you wonder why it was // written when stdlib.h has rand() function, see the recipe // "Using a true random number generator in Chapter 12, // Scratching the Tip of the Iceberg srandom(5); for (unsigned i = 0; i < 10; ++i) { boost::optional<locked_device> t = locked_device::try_lock_device(); // optional is convertible to bool if (t) { t->use(); return 0; } else { std::cout << "...trying again\n"; } } std::cout << "Failure!\n"; return -1; }
This program will output the following:
...trying again ...trying again Device is locked Success!
The Boost.Optional
class is very close to the boost::variant
class but for only one type, boost::optional<T>
has an array of chars
, where the object of type T
can be an in-place constructor. It also has a Boolean variable to remember the state of the object (is it constructed or not).
The Boost.Optional
class does not use dynamic allocation, and it does not require a default constructor for the underlying type. It is fast and considered for inclusion in the next standard of C++. The current boost::optional
implementation cannot work with C++11 rvalue references; however, there are some patches proposed to fix that.
The C++11 standard does not include the Boost.Optional
class; however, it is currently being reviewed for inclusion in the next C++ standard or in C++14.
Boost's official documentation contains more examples and describes advanced features of
Boost.Optional
(like in-place construction using the factory functions). The documentation is available at the following link:http://www.boost.org/doc/libs/1_53_0/libs/optional/doc/html/index.html
Let's play a guessing game! What can you tell about the following function?
char* vector_advance(char* val);
Should return values be deallocated by the programmer or not? Does the function attempt to deallocate the input parameter? Should the input parameter be zero-terminated, or should the function assume that the input parameter has a specified width?
And now, let's make the task harder! Take a look at the following line:
char ( &vector_advance( char (&val)[4] ) )[4];
Please do not worry; I've also been scratching my head for half an hour before getting an idea of what is happening here. vector_advance
is a function that accepts and returns an array of four elements. Is there a way to write such a function clearly?
We can rewrite the function like this:
#include <boost/array.hpp> typedef boost::array<char, 4> array4_t;array4_t& vector_advance(array4_t& val);
Here, boost::array<char, 4>
is just a simple wrapper around an array of four char elements.
This code answers all of the questions from our first example and is much more readable than the second example.
The first template parameter of boost::array
is the element type, and the second one is the size of an array. boost::array
is a fixed-size array; if you need to change the array size at runtime, use std::vector
or boost::container::vector
instead.
The Boost.Array
library just contains an array in it. That is all. Simple and efficient. The boost::array<>
class has no handwritten constructors and all of its members are public, so the compiler will think of it as a POD type.

Let's see some more examples of the usage of boost::array
:
#include <boost/array.hpp> #include <algorithm> // Functional object to increment value by one struct add_1 : public std::unary_function<char, void> { void operator()(char& c) const { ++ c; } // If you're not in a mood to write functional objects, // but don't know what does 'boost::bind(std::plus<char>(), // _1, 1)' do, then read recipe 'Binding a value as a function // parameter'. }; typedef boost::array<char, 4> array4_t; array4_t& vector_advance(array4_t& val) { // boost::array has begin(), cbegin(), end(), cend(), // rbegin(), size(), empty() and other functions that are // common for STL containers. std::for_each(val.begin(), val.end(), add_1()); return val; } int main() { // We can initialize boost::array just like an array in C++11: // array4_t val = {0, 1, 2, 3}; // but in C++03 additional pair of curly brackets is required. array4_t val = {{0, 1, 2, 3}}; // boost::array works like a usual array: array4_t val_res; // it can be default constructible and val_res = vector_advance(val); // assignable // if value type supports default construction and assignment assert(val.size() == 4); assert(val[0] == 1); /*val[4];*/ // Will trigger an assert because max index is 3 // We can make this assert work at compile-time. // Interested? See recipe 'Checking sizes at compile time' // in Chapter 4, Compile-time Tricks.' assert(sizeof(val) == sizeof(char) * array4_t::static_size); return 0; }
One of the biggest advantages of boost::array
is that it provides exactly the same performance as a normal C array. People from the C++ standard committee also liked it, so it was accepted to the C++11 standard. There is a chance that your STL library already has it (you may try to include the <array>
header and check for the availability of std::array<>
).
Boost's official documentation gives a complete list of the
Boost.Array
methods with a description of the method's complexity and throw behavior, and is available at the following link:http://www.boost.org/doc/libs/1_53_0/doc/html/boost/array.html
The
boost::array
function is widely used across recipes; for example, refer to the Binding a value as a function parameter recipe
There is a very nice present for those who like std::pair
. Boost has a library called
Boost.Tuple
, and it is just like std::pair
, but it can also work with triples, quads, and even bigger collections of types.
Perform the following steps to combine multiple values in to one:
To start working with tuples, you need to include a proper header and declare a variable:
#include <boost/tuple/tuple.hpp> #include <string> boost::tuple<int, std::string> almost_a_pair(10, "Hello"); boost::tuple<int, float, double, int> quad(10, 1.0f, 10.0, 1);
Getting a specific value is implemented via the
boost::get<N>()
function, whereN
is a zero-based index of a required value:int i = boost::get<0>(almost_a_pair); const std::string& str = boost::get<1>(almost_a_pair); double d = boost::get<2>(quad);
The
boost::get<>
function has many overloads and is used widely across Boost. We have already seen how it can be used with other libraries in the Storing multiple chosen types in a container/variable recipe.You can construct tuples using the
boost::make_tuple()
function, which is shorter to write, because you do not need to fully qualify the tuple type:using namespace boost; // Tuple comparison operators are // defined in header "boost/tuple/tuple_comparison.hpp" // Don't forget to include it! std::set<tuple<int, double, int> > s; s.insert(make_tuple(1, 1.0, 2)); s.insert(make_tuple(2, 10.0, 2)); s.insert(make_tuple(3, 100.0, 2)); // Requires C++11 auto t = make_tuple(0, -1.0, 2); assert(2 == get<2>(t)); // We can make a compile-time assert for type // of t. Interested? See chapter 'compile-time tricks'
Another function that makes life easy is
boost::tie()
. It works almost asmake_tuple
, but adds a nonconst reference for each of the passed types. Such a tuple can be used to get values to a variable from another tuple. It can be better understood from the following example:boost::tuple<int, float, double, int> quad(10, 1.0f, 10.0, 1); int i; float f; double d; int i2; // Passing values from 'quad' variables // to variables 'i', 'f', 'd', 'i2' boost::tie(i, f, d, i2) = quad; assert(i == 10); assert(i2 == 1);
Some readers may wonder why we need a tuple when we can always write our own structures with better names, for example, instead of writing boost::tuple<int, std::string>
, we can create a structure:
struct id_name_pair { int id; std::string name; };
Well, this structure is definitely more clear than boost::tuple<int, std::string>
. But what if this structure is used only twice in the code?
The main idea behind the tuple's library is to simplify template programming.

A tuple works as fast as std::pair
(it does not allocate memory on a heap and has no virtual functions). The C++ committee found this class to be very useful and it was included in STL; you can find it in a C++11-compatible STL implementation in the header file <tuple>
(don't forget to replace all the boost::
namespaces with std::
).
The current Boost implementation of a tuple does not use variadic templates; it is just a set of classes generated by a script. There is an experimental version that uses C++11 rvalues and an emulation of them on C++03 compilers, so there is a chance that Boost 1.54 will be shipped with faster implementation of tuples.
The experimental version of tuples can be found at the following link:
Boost's official documentation contains more examples, information about performance, and abilities of
Boost.Tuple
. It is available at the following link:http://www.boost.org/doc/libs/1_53_0/libs/tuple/doc/tuple_users_guide.html
The Converting all tuple elements to strings recipe in Chapter 8, Metaprogramming, shows some advanced usages of tuples
This recipe and the next one are devoted to a very interesting library, whose functionality at first glance looks like some kind of magic. This library is called Boost.Bind
and it allows you to easily create new functional objects from functions, member functions, and functional objects, also allowing the reordering of the initial function's input parameters and binding some values or references as function parameters.
Let's start with an example. You are working with a vector of integral types provided by some other programmer. That integral type has only one operator,
+
, but your task is to multiply a value by two. Withoutbind
this can be achieved with the use of a functional object:class Number{}; inline Number operator + (Number, Number); // Your code starts here struct mul_2_func_obj: public std::unary_function<Number, Number> { Number operator()(Number n1) const { return n1 + n1; } }; void mul_2_impl1(std::vector<Number>& values) { std::for_each(values.begin(), values.end(), mul_2_func_obj()); }
With
Boost.Bind
, it would be as follows:#include <boost/bind.hpp> #include <functional> void mul_2_impl2(std::vector<Number>& values) { std::for_each(values.begin(), values.end(), boost::bind(std::plus<Number>(), _1, _1)); }
By the way, we can easily make this function more generic:
template <class T> void mul_2_impl3(std::vector<T>& values) { std::for_each(values.begin(), values.end(), boost::bind(std::plus<T>(), _1, _1)); }
Let's take a closer look at the mul_2
function. We provide a vector of values to it, and for each value it applies a functional object returned by the bind()
function. The bind()
function takes in three parameters; the first parameter is an instance of the std::plus<Number>
class (which is a functional object). The second and third parameters are placeholders. The placeholder _1
substitutes the argument with the first input argument of the resulting functional object. As you might guess, there are many placeholders; placeholder _2
means substituting the argument with the second input argument of the resulting functional object, and the same also applies to placeholder _3
. Well, seems you've got the idea.
Just to make sure that you've got the whole idea and know where bind can be used, let's take a look at another example.
We have two classes, which work with some sensor devices. The devices and classes are from different vendors, so they provide different APIs. Both classes have only one public method watch
, which accepts a functional object:
class Device1 { private: short temperature(); short wetness(); int illumination(); int atmospheric_pressure(); void wait_for_data(); public: template <class FuncT> void watch(const FuncT& f) { for(;;) { wait_for_data(); f( temperature(), wetness(), illumination(), atmospheric_pressure() ); } } }; class Device2 { private: short temperature(); short wetness(); int illumination(); int atmospheric_pressure(); void wait_for_data(); public: template <class FuncT> void watch(const FuncT& f) { for(;;) { wait_for_data(); f( wetness(), temperature(), atmospheric_pressure(), illumination() ); } } };
The Device1::watch
and Device2::watch
functions pass values to a functional object in a different order.
Some other libraries provide a function, which is used to detect storms, and throws an exception when the risk of a storm is high enough:
void detect_storm(int wetness, int temperature, int atmospheric_pressure);
Your task is to provide a storm-detecting function to both of the devices. Here is how it can be achieved using the bind
function:
Device1 d1; // resulting functional object will silently ignore // additional parameters passed to function call d1.watch(boost::bind(&detect_storm, _2, _1, _4)); ... Device2 d2; d2.watch(boost::bind(&detect_storm, _1, _2, _3));
The Boost.Bind
library provides good performance because it does not use dynamic allocations and virtual functions. It is useful even when the C++11 lambda functions are not usable:
template <class FuncT> void watch(const FuncT& f) { f(10, std::string("String")); f(10, "Char array"); f(10, 10); } struct templated_foo { template <class T> void operator()(T, int) const { // No implementation, just showing that bound // functions still can be used as templated } }; void check_templated_bind() { // We can directly specify return type of a functional object // when bind fails to do so watch(boost::bind<void>(templated_foo(), _2, _1)); }
Bind is a part of the C++11 standard. It is defined in the <functional>
header and may slightly differ from the Boost.Bind
implementation (however, it will be at least as effective as Boost's implementation).
If you work with the STL library a lot and use the <algorithm>
header, you will definitely write a lot of functional objects. You can construct them using a set of STL adapter functions such as bind1st
, bind2nd
, ptr_fun
, mem_fun
, and mem_fun_ref
, or you can write them by hand (because adapter functions look scary). Here is some good news: Boost.Bind
can be used instead of all of those functions and it provides a more human-readable syntax.
Read the previous recipe to get an idea of placeholders, or just make sure that you are familiar with C++11 placeholders. Knowledge of STL functions and algorithms is welcomed.
Let's see some examples of the usage of Boost.Bind
along with traditional STL classes:
Count values greater than or equal to 5 as shown in the following code:
boost::array<int, 12> values = {{1, 2, 3, 4, 5, 6, 7, 100, 99, 98, 97, 96}}; std::size_t count0 = std::count_if(values.begin(), values.end(), std::bind1st(std::less<int>(), 5)); std::size_t count1 = std::count_if(values.begin(), values.end(), boost::bind(std::less<int>(), 5, _1)); assert(count0 == count1);
This is how we could count empty strings:
boost::array<std::string, 3> str_values = {{"We ", "are", " the champions!"}}; count0 = std::count_if(str_values.begin(), str_values.end(), std::mem_fun_ref(&std::string::empty)); count1 = std::count_if(str_values.begin(), str_values.end(), boost::bind(&std::string::empty, _1)); assert(count0 == count1);
Now let's count strings with a length less than
5
:// That code won't compile! And it is hard to understand //count0 = std::count_if(str_values.begin(), //str_values.end(), //std::bind2nd( // std::bind1st( // std::less<std::size_t>(), // std::mem_fun_ref(&std::string::size) // ) //, 5 //)); // This will become much more readable, // when you get used to bind count1 = std::count_if(str_values.begin(), str_values.end(), boost::bind(std::less<std::size_t>(), boost::bind(&std::string::size, _1), 5)); assert(2 == count1);
Compare the strings:
std::string s("Expensive copy constructor of std::string will be called when binding"); count0 = std::count_if(str_values.begin(), str_values.end(), std::bind2nd(std::less<std::string>(), s)); count1 = std::count_if(str_values.begin(), str_values.end(), boost::bind(std::less<std::string>(), _1, s)); assert(count0 == count1);
The boost::bind
function returns a functional object that stores a copy of the bound values and a copy of the original functional object. When the actual call to operator()
is performed, the stored parameters are passed to the original functional object along with the parameters passed at the time of call.
Take a look at the previous examples. When we are binding values, we copy a value into a functional object. For some classes this operation is expensive. Is there a way to bypass copying?
Yes, there is! And the Boost.Ref
library will help us here! It contains two functions, boost::ref()
and boost::cref()
, the first of which allows us to pass a parameter as a reference, and the second one passes the parameter as a constant reference. The ref()
and cref()
functions just construct an object of type reference_wrapper<T>
or reference_wrapper<const T>
, which is implicitly convertible to a reference type. Let's change our previous examples:
#include <boost/ref.hpp> ... std::string s("Expensive copy constructor of std::string now " "won't be called when binding"); count0 = std::count_if(str_values.begin(), str_values.end(), std::bind2nd(std::less<std::string>(), boost::cref(s))); count1 = std::count_if(str_values.begin(), str_values.end(), boost::bind(std::less<std::string>(), _1, boost::cref(s))); assert(count0 == count1);
Just one more example to show you how boost::ref
can be used to concatenate strings:
void wierd_appender(std::string& to, const std::string& from) { to += from; }; std::string result; std::for_each(str_values.cbegin(), str_values.cend(), boost::bind(&wierd_appender, boost::ref(result), _1)); assert(result == "We are the champions!");
The functions ref
and cref
(and bind
) are accepted to the C++11 standard and defined in the <functional>
header in the std::
namespace. None of these functions dynamically allocate memory in the heap and they do not use virtual functions. The objects returned by them are easy to optimize and they do not apply any optimization barriers for good compilers.
STL implementations of those functions may have additional optimizations to reduce compilation time or just compiler-specific optimizations, but unfortunately, some STL implementations miss the functionality of Boost versions. You may use the STL version of those functions with any Boost library, or even mix Boost and STL versions.
The
Boost.Bind
library is used widely across this book; see Chapter 6, Manipulating Tasks, and Chapter 5, Multithreading, for more examplesThe official documentation contains many more examples and a description of advanced features at http://www.boost.org/doc/libs/1_53_0/libs/bind/bind.html
One of the greatest features of the C++11 standard is rvalue references. This feature allows us to modify temporary objects, "stealing" resources from them. As you can guess, the C++03 standard has no rvalue references, but using the Boost.Move
library you can write some portable code that uses them, and even more, you actually get started with the emulation of move semantics.
Now, let's take a look at the following examples:
Imagine that you have a class with multiple fields, some of which are STL containers.
namespace other { // Its default construction is cheap/fast class characteristics{}; } // namespace other struct person_info { // Fields declared here // ... bool is_male_; std::string name_; std::string second_name_; other::characteristics characteristic_; };
It is time to add the move assignment and move constructors to it! Just remember that in C++03, STL containers have neither move operators nor move constructors.
The correct implementation of the move assignment is the same as
swap
andclear
(if an empty state is allowed). The correct implementation of the move constructor is close to the default construct andswap
. So, let's start with theswap
member function:#include <boost/swap.hpp> void swap(person_info& rhs) { std::swap(is_male_, rhs.is_male_); name_.swap(rhs.name_); second_name_.swap(rhs.second_name_); boost::swap(characteristic_, rhs.characteristic_); }
Now put the following macro in the
private
section:BOOST_COPYABLE_AND_MOVABLE(classname)
Write a copy constructor.
Write a copy assignment, taking the parameter as
BOOST_COPY_ASSIGN_REF(classname)
.Write a move constructor and a move assignment, taking the parameter as
BOOST_RV_REF(classname)
:struct person_info {
// Fields declared here // ... private: BOOST_COPYABLE_AND_MOVABLE(person_info) public: // For the simplicity of example we will assume that // person_info default constructor and swap are very // fast/cheap to call person_info() {} person_info(const person_info& p) : is_male_(p.is_male_) , name_(p.name_) , second_name_(p.second_name_) , characteristic_(p.characteristic_) {} person_info(BOOST_RV_REF(person_info) person) { swap(person); } person_info& operator=(BOOST_COPY_ASSIGN_REF(person_info) person) { if (this != &person) { person_info tmp(person); swap(tmp); } return *this; } person_info& operator=(BOOST_RV_REF(person_info) person) { if (this != &person) { swap(person); person_info tmp; tmp.swap(person); } return *this; } void swap(person_info& rhs) { // … } };Now we have a portable, fast implementation of the move assignment and move construction operators of the
person_info
class.
Here is an example of how the move assignment can be used:
person_info vasya; vasya.name_ = "Vasya"; vasya.second_name_ = "Snow"; vasya.is_male_ = true; person_info new_vasya(boost::move(vasya)); assert(new_vasya.name_ == "Vasya"); assert(new_vasya.second_name_ == "Snow"); assert(vasya.name_.empty()); assert(vasya.second_name_.empty()); vasya = boost::move(new_vasya); assert(vasya.name_ == "Vasya"); assert(vasya.second_name_ == "Snow"); assert(new_vasya.name_.empty()); assert(new_vasya.second_name_.empty());
The Boost.Move
library is implemented in a very efficient way. When the C++11 compiler is used, all the macros for rvalues emulation will be expanded to C++11-specific features, otherwise (on C++03 compilers) rvalues will be emulated using specific datatypes and functions that never copy passed values nor called any dynamic memory allocations or virtual functions.
Have you noticed the boost::swap
call? It is a really helpful utility function, which will first search for a swap
function in the namespace of a variable (the namespace other::
), and if there is no swap function for the characteristics
class, it will use the STL implementation of swap.
More information about emulation implementation can be found on the Boost website and in the sources of the
Boost.Move
library at http://www.boost.org/doc/libs/1_53_0/doc/html/move.html.The
Boost.Utility
library is the one that containsboost::utility
, and it has many useful functions and classes. Refer to its documentation at http://www.boost.org/doc/libs/1_53_0/libs/utility/utility.htm.The Initializing the base class by the member of the derived recipe in Chapter 3, Managing Resources.
The Making a noncopyable class recipe.
In the Making a noncopyable but movable class recipe, there is more info about
Boost.Move
and some examples on how we can use the movable objects in containers in a portable and efficient way.
You must have almost certainly encountered situations where providing a copy constructor and move assignment operator for a class will require too much work, or where a class owns some resources that must not be copied for technical reasons:
class descriptor_owner { void* descriptor_; public: explicit descriptor_owner(const char* params); ~descriptor_owner() { system_api_free_descriptor(descriptor_); } };
The C++ compiler, in the case of the previous example, will generate a copy constructor and an assignment operator, so the potential user of the descriptor_owner
class will be able to create the following awful things:
descriptor_owner d1("O_o"); descriptor_owner d2("^_^"); // Descriptor of d2 was not correctly freed d2 = d1; // destructor of d2 will free the descriptor // destructor of d1 will try to free already freed descriptor
To avoid such situations, the boost::noncopyable
class was invented. If you derive your own class from it, the copy constructor and assignment operator won't be generated by the C++ compiler:
#include <boost/noncopyable.hpp> class descriptor_owner_fixed : private boost::noncopyable { …
Now the user won't be able to do bad things:
descriptor_owner_fixed d1("O_o"); descriptor_owner_fixed d2("^_^"); // Won't compile d2 = d1; // Won't compile either descriptor_owner_fixed d3(d1);
A sophisticated reader will tell me that we can achieve exactly the same result by making a copy constructor and an assignment operator of descriptor_owning_fixed
private, or just by defining them without actual implementation. Yes, you are correct. Moreover, this is the current implementation of the boost::noncopyable
class. But boost::noncopyable
also serves as good documentation for your class. It never raises questions such as "Is the copy constructor body defined elsewhere?" or "Does it have a nonstandard copy constructor (with a nonconst referenced parameter)?".
The Making a noncopyable but movable class recipe will give you ideas on how to allow unique ownership of a resource in C++03 by moving it
You may find a lot of helpful functions and classes in the
Boost.Utility
library's official documentation at http://www.boost.org/doc/libs/1_53_0/libs/utility/utility.htmThe Initializing the base class by the member of the derived recipe in Chapter 3, Managing Resources
The Using the C++11 move emulation recipe
Now imagine the following situation: we have a resource that cannot be copied, which should be correctly freed in a destructor, and we want to return it from a function:
descriptor_owner construct_descriptor() { return descriptor_owner("Construct using this string"); }
Actually, you can work around such situations using the swap
method:
void construct_descriptor1(descriptor_owner& ret) { descriptor_owner("Construct using this string").swap(ret); }
But such a workaround won't allow us to use descriptor_owner
in STL or Boost containers. And by the way, it looks awful!
It is highly recommended to know at least the basics of C++11 rvalue references. Reading the Using the C++11 move emulation recipe is also recommended.
Those readers who use C++11 already know about the move-only classes (like std::unique_ptr
or std::thread
). Using such an approach, we can make a move-only descriptor_owner
class:
class descriptor_owner1 { void* descriptor_; public: descriptor_owner1() : descriptor_(NULL) {} explicit descriptor_owner1(const char* param) : descriptor_(strdup(param)) {} descriptor_owner1(descriptor_owner1&& param) : descriptor_(param.descriptor_) { param.descriptor_ = NULL; } descriptor_owner1& operator=(descriptor_owner1&& param) { clear(); std::swap(descriptor_, param.descriptor_); return *this; } void clear() { free(descriptor_); descriptor_ = NULL; } bool empty() const { return !descriptor_; } ~descriptor_owner1() { clear(); } }; // GCC compiles the following in with -std=c++0x descriptor_owner1 construct_descriptor2() { return descriptor_owner1("Construct using this string"); } void foo_rv() { std::cout << "C++11\n"; descriptor_owner1 desc; desc = construct_descriptor2(); assert(!desc.empty()); }
This will work only on C++11 compatible compilers. That is the right moment for Boost.Move
! Let's modify our example so it can be used on C++03 compilers.
According to the documentation, to write a movable but noncopyable type in portable syntax, we need to follow these simple steps:
Put the
BOOST_MOVABLE_BUT_NOT_COPYABLE(classname)
macro in theprivate
section:class descriptor_owner_movable { void* descriptor_; BOOST_MOVABLE_BUT_NOT_COPYABLE(descriptor_owner_movable)
Write a move constructor and a move assignment, taking the parameter as
BOOST_RV_REF(classname)
:#include <boost/move/move.hpp> public: descriptor_owner_movable() : descriptor_(NULL) {} explicit descriptor_owner_movable(const char* param) : descriptor_(strdup(param)) {} descriptor_owner_movable( BOOST_RV_REF(descriptor_owner_movable) param) : descriptor_(param.descriptor_) { param.descriptor_ = NULL; } descriptor_owner_movable& operator=( BOOST_RV_REF(descriptor_owner_movable) param) { clear(); std::swap(descriptor_, param.descriptor_); return *this; } // ... }; descriptor_owner_movable construct_descriptor3() { return descriptor_owner_movable("Construct using this string"); }
Now we have a movable but noncopyable class that can be used even on C++03 compilers and in Boost.Containers
:
#include <boost/container/vector.hpp> ... // Following code will work on C++11 and C++03 compilers descriptor_owner_movable movable; movable = construct_descriptor3(); boost::container::vector<descriptor_owner_movable> vec; vec.resize(10); vec.push_back(construct_descriptor3()); vec.back() = boost::move(vec.front());
But unfortunately, C++03 STL containers still won't be able to use it (that is why we used a vector from Boost.Containers
in the previous example).
If you want to use Boost.Containers
on C++03 compilers and STL containers, on C++11 compilers you can use the following simple trick. Add the header file to your project with the following content:
// your_project/vector.hpp // Copyright and other stuff goes here // include guards #ifndef YOUR_PROJECT_VECTOR_HPP #define YOUR_PROJECT_VECTOR_HPP #include <boost/config.hpp> // Those macro declared in boost/config.hpp header // This is portable and can be used with any version of boost // libraries #if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) // We do have rvalues #include <vector> namespace your_project_namespace { using std::vector; } // your_project_namespace #else // We do NOT have rvalues #include <boost/container/vector.hpp> namespace your_project_namespace { using boost::container::vector; } // your_project_namespace #endif // !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) #endif // YOUR_PROJECT_VECTOR_HPP
Now you can include <your_project/vector.hpp>
and use a vector from the namespace your_project_namespace
:
your_project_namespace::vector<descriptor_owner_movable> v; v.resize(10); v.push_back(construct_descriptor3()); v.back() = boost::move(v.front());
But beware of compiler- and STL-implementation-specific issues! For example, this code will compile on GCC 4.7 in C++11 mode only if you mark the move constructor, destructor, and move assignment operators with noexcept
.
The Reducing code size and increasing performance of user-defined types (UDTs) in C++11 recipe in Chapter 10, Gathering Platform and Compiler Information, for more info on
noexcept
More information about
Boost.Move
can be found on Boost's website http://www.boost.org/doc/libs/1_53_0/doc/html/move.html