Book Image

Boost C++ Application Development Cookbook - Second Edition

By : Anton Polukhin Alekseevic
Book Image

Boost C++ Application Development Cookbook - Second Edition

By: Anton Polukhin Alekseevic

Overview of this book

If you want to take advantage of the real power of Boost and C++ and avoid the confusion about which library to use in which situation, then this book is for you. Beginning with the basics of Boost C++, you will move on to learn how the Boost libraries simplify application development. You will learn to convert data such as string to numbers, numbers to string, numbers to numbers and more. Managing resources will become a piece of cake. You’ll see what kind of work can be done at compile time and what Boost containers can do. 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. From manipulating images to graphs, directories, timers, files, networking – everyone will find an interesting topic. Be sure that knowledge from this book won’t get outdated, as more and more Boost libraries become part of the C++ Standard.
Table of Contents (19 chapters)
Title Page
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Storing any value in a container/variable


If you have been programming in Java, C#, or Delphi, you will definitely miss the ability of creating 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++:

typedef std::unique_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; 

Getting ready

We'll be working with the header-only library. The basic knowledge of C++ is all you need for this recipe.

How to do it...

Boost offers a solution, the Boost.Any library, that 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); 
    some_values.push_back("Hello there!"); 
    some_values.push_back(std::string("Wow!"));

    std::string& s = boost::any_cast<std::string&>(some_values.back()); 
    s += " That is great!"; 
    std::cout << s; 
} 

Great, isn't it? By the way, it has an empty state, which could be checked using the empty() member function (just like in standard library containers).

You can get the value from boost::any using two approaches:

void example() {
    boost::any variable(std::string("Hello world!"));

    // 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);

    // Never throws. If actual value in variable is not a std::string
    // will return an NULL pointer.
    std::string* s2 = boost::any_cast<std::string>(&variable);
}

How it works...

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 types). To use this library you do not really need to know its internal implementation in detail, but here's a quick glance at the type erasure technique for the curious.

On the assignment of some variable of type T, Boost.Any instantiates a holder<T> type that may store a value of the specified type T and is derived from some base-type placeholder:

template<typename ValueType>
struct holder : public placeholder {
    virtual const std::type_info& type() const {
         return typeid(ValueType);
    }
     ValueType held;
};

A placeholder type has virtual functions for getting std::type_info of a stored type T and for cloning a stored type:

struct placeholder {
    virtual ~placeholder() {}
    virtual const std::type_info& type() const = 0;
};

boost::any stores ptr-- a pointer to placeholder. When any_cast<T>() is used, boost::any checks that calling ptr->type() gives std::type_info equal to typeid(T) and returns static_cast<holder<T>*>(ptr)->held.

There's more...

Such flexibility never comes without any cost. Copy constructing, value constructing, copy assigning, and assigning values to instances of boost::any do dynamic memory allocation; all the type casts do RunTime Type Information (RTTI) checks; boost::any uses virtual functions a lot. If you are keen on performance, the next recipe will give you an idea of how to achieve almost the same results without dynamic allocations and RTTI usage.

boost::any makes use of rvalue references but can not be used in constexpr.

The Boost.Any library was accepted into C++17. If your compiler is C++17 compatible and you wish to avoid using Boost for any, just replace the boost namespace with namespace std and include <any> instead of <boost/any.hpp>. Your standard library implementation may work slightly faster if you are storing tiny objects in std::any.

Note

std::any has the reset() function instead of clear() and has_value() instead of empty(). Almost all exceptions in Boost derived from the std::exception class or from its derivatives, for example, boost::bad_any_cast is derived from std::bad_cast. It means that you can catch almost all Boost exceptions using catch (const std::exception& e).

See also

  • Boost's official documentation may give you some more examples; it can be found at http://boost.org/libs/any
  • The Using a safer way to work with a container that stores multiple chosen types recipe for more info on the topic