Book Image

Boost C++ Application Development Cookbook

By : Antony Polukhin
Book Image

Boost C++ Application Development Cookbook

By: Antony Polukhin

Overview of this book

<p>Boost libraries are developed by professionals, tested on multiple platforms and processor architectures, and contain reliable solutions for a wide range of tasks. This Cookbook takes you on a journey of simplifying the process of application development and guides you through writing perfect applications fast.</p> <p>"Boost C++ Application Development Cookbook" provides you with a number of clear step-by-step recipes that will help you take advantage of the real power of Boost and C++, while giving you a good grounding in using it in any project.</p> <p>"Boost C++ Application Development Cookbook" looks at the Boost libraries, and breaks down the mystery and confusion about which library to use in which situation. It will take you through a number of clear, practical recipes that will help you to take advantage of the readily available solutions.</p> <p>Boost C++ Application Development Cookbook starts with teaching the basics of Boost libraries that are now mostly part of C++11 and leave no chance for memory leaks. Managing resources will become a piece of cake. We’ll see what kind of work can be done at compile time and what Boost containers can do. Do you think multithreading is a burden? Not with Boost. Think writing portable and fast servers is impossible? You’ll be surprised! Compilers and operating systems differ too much? Not with Boost. From manipulating images to graphs, directories, timers, files, strings – everyone will find an interesting topic.</p> <p>You will learn everything for the development of high quality fast and portable applications. Write a program once and then you can use it on Linux, Windows, MacOS, Android operating systems.</p>
Table of Contents (19 chapters)
Boost C++ Application Development Cookbook
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Binding a value as a function parameter


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.

Getting ready

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.

How to do it...

Let's see some examples of the usage of Boost.Bind along with traditional STL classes:

  1. 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);
  2. 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);
  3. 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);
  4. 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);

How it works...

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.

There's more...

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.

See also