Sei sulla pagina 1di 447

Table of Contents on/off Homepage Feed Contact

Front page
Chapter 1: Introduction
Table of Contents Boris Schling Front page

Front page
Chapter 1: Introduction
Chapter 2: Smart Pointers
The Boost C++ Libraries
Chapter 3: Function Objects
Chapter 4: Event Handling Table of Contents Chapter 1: Introduction
Chapter 5: String Handling Chapter 2: Smart Pointers
Chapter 6: Multithreading Chapter 3: Function Objects
Chapter 4: Event Handling
Chapter 7: Asynchronous Input and Output Chapter 5: String Handling
Chapter 8: Interprocess Communication Chapter 6: Multithreading
Chapter 9: Filesystem Chapter 7: Asynchronous Input and Output
Chapter 10: Date and Time Chapter 8: Interprocess Communication
Chapter 9: Filesystem
Chapter 11: Serialization Chapter 10: Date and Time
Chapter 12: Parser Chapter 11: Serialization
Chapter 13: Containers Chapter 12: Parser
Chapter 14: Data Structures Chapter 13: Containers
Chapter 14: Data Structures
Chapter 15: Error Handling Chapter 15: Error Handling
Chapter 16: Cast Operators Chapter 16: Cast Operators

This book is licensed under a Creative Commons License.

You can buy this book as a PDF file in A4 and US Letter format or as an ePub file
for eBook readers.

This book has been translated from German to English by Andreas Masur (Homepage).

Content

What you will learn This book is an introduction to the Boost C++ Libraries which
complement the C++ standard by adding functions helpful in practice. As
the Boost C++ Libraries are based on the C++ standard, they are
implemented using state-of-the-art C++. They are platform independent
and are supported on many operating systems including Windows and
Linux by a large developer community.

The Boost C++ Libraries enable you to boost your productivity as a C++
developer. For example, you can benefit from smart pointers which help
you to write more reliable code or use one of the many libraries to
develop platform independent network applications. Since many Boost
C++ Libraries are going to be incorporated into the next version of the
C++ standard, you can prepare yourself starting today.

Requirements

What you should know Since the Boost C++ Libraries are based on as well as extending the C++
standard, you should know the C++ standard well. You should understand
and be able to use containers, iterators and algorithms and ideally should
have heard of concepts such as RAII, function objects or predicates. The
better you know the C++ standard, the more you are able to benefit
form the Boost C++ Libraries.

Copyright 2008-2010 Boris Schling


Version 1.0 / 01April2010
http://en.highscore.de/cpp/boost/
Boris Schling Frontpage
Front page
Chapter 1: Introduction

The Boost C++ Libraries


Table of Contents Chapter 1: Introduction
Chapter 2: Smart Pointers
Chapter 3: Function Objects
Chapter 4: Event Handling
Chapter 5: String Handling
Chapter 6: Multithreading
Chapter 7: Asynchronous Input and Output
Chapter 8: Interprocess Communication
Chapter 9: Filesystem
Chapter 10: Date and Time
Chapter 11: Serialization
Chapter 12: Parser
Chapter 13: Containers
Chapter 14: Data Structures
Chapter 15: Error Handling
Chapter 16: Cast Operators

This book is licensed under a Creative Commons License.

You can buy this book as a PDF file in A4 and US Letter format or as an ePub file for eBook readers.

This book has been translated from German to English by Andreas Masur (Homepage).

Content

What you will learn This book is an introduction to the Boost C++ Libraries which complement the C++ standard by adding functions helpful in
practice. As the Boost C++ Libraries are based on the C++ standard, they are implemented using state-of-the-art C++.
They are platform independent and are supported on many operating systems including Windows and Linux by a large
developer community.

The Boost C++ Libraries enable you to boost your productivity as a C++ developer. For example, you can benefit from
smart pointers which help you to write more reliable code or use one of the many libraries to develop platform independent
network applications. Since many Boost C++ Libraries are going to be incorporated into the next version of the C++
standard, you can prepare yourself starting today.

Requirements

What you should know Since the Boost C++ Libraries are based on as well as extending the C++ standard, you should know the C++ standard
well. You should understand and be able to use containers, iterators and algorithms and ideally should have heard of
concepts such as RAII, function objects or predicates. The better you know the C++ standard, the more you are able to
benefit form the Boost C++ Libraries.

Copyright 2008-2010 Boris Schling


Version 1.0 / 01April2010
http://en.highscore.de/cpp/boost/
The Boost C++ Libraries Chapter1:1:
Chapter Introduction
Introduction
Chapter 2: Smart Pointers

Chapter 1: Introduction
Table of Contents 1.1 C++ and Boost
1.2 Development Process
1.3 Installation
1.4 Overview

This book is licensed under a Creative Commons License.

1.1 C++ and Boost

The Boost C++ Libraries are a collection of modern libraries based on the C++ standard. The source code is released
under the Boost Software License allowing to use, modify and distribute the libraries for free. The libraries are platform
independent and support most popular as well as many lesser known compilers.

The Boost community is responsible for developing and publishing the Boost C++ Libraries. It consists of a relatively large
group of C++ developers from around the world coordinated through the web site www.boost.org as well as several mailing
lists. The mission statement of the community is to develop and collect libraries of high-quality that complement the C++
standard. Libraries that prove of value and become important for the development of C++ applications stand a good
chance to get included in the C++ standard someday.

The Boost community emerged around 1998 when the first revision of the C++ standard was released. It has grown
continuously since then and nowadays plays a big role in the standardization of C++. Even though there is no direct
relation between the Boost community and the standardization committee, some of the developers are active in both
groups. The next revision of the C++ standard, which is most likely approved in 2011, is going to be extended by a couple
of libraries that have their roots in the Boost community.

Boost C++ Libraries are a good choice to increase the productivity of C++ projects after exhausting the C++ standard.
Since C++ has evolved after the current revision of the C++ standard originated in 2003, Boost C++ Libraries offer many
new features. Without waiting for the next revision of the C++ standard, progress made in the evolution of C++ can be
utilized immediately thanks to the Boost C++ Libraries.

Due to the excellent reputation the Boost C++ Libraries have, being well grounded in using them certainly proves to be of
value occupationally. It is not unusual to be asked about the Boost C++ Libraries during an interview since developers who
know these libraries are usually also fond with the latest innovations of C++ and are able to write and understand modern
C++ code.
1.2 Development Process

The development of the Boost C++ Libraries is only possible because individual developers or organizations support them
with great engagement. Since Boost only accepts libraries that solve existing problems, exhibit a convincing design, are
developed using modern C++ and are documented in an understandable way, each Boost C++ Library has a lot of work
behind it.

C++ developers can engage themselves in the Boost community and propose new libraries. However, in order to convert
an idea into a Boost C++ Library, a lot of time and effort needs to be invested. It is of vital importance to discuss the
requirements and possible solutions with other developers and potential users in the Boost mailing lists.

Besides libraries that seem to appear from nowhere, it is also possible to nominate existing C++ libraries for the inclusion
into Boost. However, since the requirements for these libraries are the same as for libraries developed for Boost in
particular, there may be many changes required.

Whether or not a library gets accepted into Boost, depends on the outcome of the review process. Developers of libraries
can apply for a review which usually takes places over the course of 10 days. During this time frame other developers are
requested to rate the library. Based on the number of positive and negative reviews, the review manager decides whether
or not the library is accepted into Boost. Since some developers are exposed to the library for the first time during the
review, it is not uncommon that modifications to the library are requested during the time frame of the review.

If a library is rejected due to technical reasons, it is still possible to revise the library and request a new review for an
updated version. However, if a library is rejected because it does not solve any practical problem or because it provides an
unconvincing solution to an existing problem, there is a good chance that it will be again rejected during another review.

Because new libraries can be accepted at any time, a new version of the Boost C++ Libraries is released every three
months. This book covers libraries found in version 1.42.0 which was released in February 2010.

Please note that there exists additional libraries that have been already accepted but are not part of the official release of
the Boost C++ Libraries yet. They have to be manually installed until they get included.

1.3 Installation

The Boost C++ Libraries come as source code. While most of the libraries consist solely of header files that can be directly
used, some of the libraries requires compilation. In order to make the installation process as easy as possible, an
automated installation process using Boost Jam is available. Instead of validating and compiling individual libraries
separately, Boost Jam installs the complete set automatically. It supports many operating systems and compilers and
knows how to compile each individual library based on appropriate configuration files.

To automatically install the Boost C++ Libraries with the aid of Boost Jam, an application named bjam is utilized which is
also available as source code. For some operating systems, including Windows and Linux, precompiled binaries of bjam are
available as well.

In order to compile bjam itself, a simple script named build is executed which is available with the source code and is
provided for different operating systems as well. For Windows, it is implemented as the batch file build.bat. For Linux, the
file is called build.sh.

If build is called without any command line option, the script tries to find a suitable compiler to generate bjam. Using a
command line switch, denoted as toolset, a particular compiler can be selected though. For Windows, build supports the
toolsets vc7, vc8 and vc9 to select different versions of the Microsoft C++ compiler. To compile bjam with the C++
compiler from Visual Studio 2008, the command build vc9 needs to be issued. For Linux, the toolsets gcc and intel-linux
are supported, amongst others, to select the C++ compiler of GCC and Intel, respectively.

The application bjam must be copied to the local Boost directory - disregarding whether it was compiled or downloaded as
a precompiled binary. bjam can then be started without any command line option to compile and install the Boost C++
Libraries. Since the default options - used in this case - are not always the best choice, the most important options are
listed below:

The declaration of stage or install specifies whether the Boost C++ Libraries are installed in a subdirectory named
stage or system-wide. The meaning of system-wide depends on the operating system. In Windows, the target
directory is C:\Boost; in Linux it is /usr/local. The target directory can also be explicitly specified using the --prefix
option.

If bjam is called without any command line options, it will search for a suitable C++ compiler itself. A specific
compiler can be selected using the --toolset option. To specify the Microsoft C++ compiler from Visual Studio 2008 in
Windows, bjam needs to be called with the --toolset=msvc-9.0 option. To specify the GCC compiler in Linux, the
option --toolset=gcc must be selected.

The command line option --build-type determines which builds of the libraries are created. By default, this option is
set to minimal, meaning that only release builds are created. This may become an issue for developers who want to
create debug builds of their projects with Visual Studio or GCC. Since these compilers automatically try to link
against the debug builds of the Boost C++ Libraries, an error message is displayed accordingly. In this case the
option --build-type should be set to complete to generate both debug and release builds of the Boost C++ Libraries
which, however, will take much longer.

To create both debug and release builds of the Boost C++ Libraries using the C++ compiler from Visual Studio 2008 and
install them in the directory D:\Boost, the command executed is bjam --toolset=msvc-9.0 --build-type=complete --
prefix=D:\Boost install. To create them in Linux using the default directory, the command executed is bjam --
toolset=gcc --build-type=complete install.

There exist many other command line options which can be used to specify in detail how to compile the Boost C++
Libraries. I typically use the following command in Windows: bjam --toolset=msvc-9.0 debug release link=static
runtime-link=shared install. debug and release cause both debug and release builds to be generated. link=static only
creates static libraries. runtime-link=shared specifies that the C++ runtime library is dynamically linked which is the
default setting for C++ projects in Visual Studio 2008.

1.4 Overview

Version 1.42.0 of the Boost C++ Libraries contains more than 90 libraries out of which this book discusses the following
libraries in more detail:
Table1.1.Covered Libraries
Boost C++ Library C++ Short Description
Standard

Boost.Any Boost.Any provides a data type named boost::any that allows to store arbitrary
types. For example, a variable of type boost::any can first store a value of type int
before replacing it with a string of type std::string.
Boost.Array TR1 Boost.Array allows treating C++ arrays just like containers from the C++ standard.

Boost.Asio TR2 Boost.Asio allows to develop applications that process data asynchronously such as
network applications.
Boost.Bimap Boost.Bimap provides a class named boost::bimap which is similar to std::map.
The crucial difference is that boost::bimap allows to search for both key and value.
Boost.Bind TR1 Boost.Bind is kind of an adapter allowing to pass functions as template parameters
even if the function signature is incompatible with the template parameter.
Boost.Conversion Boost.Conversion provides three casting operators to perform downcasts, cross
casts and to convert between values of different numeric types.
Boost.DateTime Boost.DateTime can be used to process, read and write date and time values with a
flexible formatting.
Boost.Exception Boost.Exception allows adding additional data to thrown exceptions in order to
provide more information in the catch handler. This helps easing the debugging
process and allows better responding to exceptional cases.
Boost.Filesystem TR2 Boost.Filesystem offers a class for processing of path information and also contains
several functions to access files and directories.
Boost.Format Boost.Format replaces the std::printf() function with a type-safe and extendable
boost::format class.
Boost.Function TR1 Boost.Function simplifies the definition of function pointers.

Boost.Interprocess Boost.Interprocess allows applications to communicate via shared memory in a fast


and efficient manner.
Boost.Lambda Boost.Lambda allows the definition of anonymous functions. Code is declared and
executed inline to avoid separate function calls.
Boost.Multiindex Boost.Multiindex allows defining new containers that can support multiple interfaces
such as the ones from std::vector and std::map.
Boost.NumericConversion Boost.NumericConversion provides a cast operator to safely convert between values
of different numeric types without generating an overflow or underflow condition.
Boost.PointerContainer Boost.PointerContainer provides containers optimized for the management of
dynamically allocated objects.

Boost.Ref TR1 The adapters of Boost.Ref allow passing references to uncopyable objects to
functions that expect copies.
Boost.Regex TR1 Boost.Regex offers functions to search text via regular expressions.

Boost.Serialization Via Boost.Serialization, objects can be serialized and e.g. stored in files that can be
loaded later on.
Boost.Signals Boost.Signal is a framework for event handling and is based on the so-called
signal/slot concept: Functions are associated with signals and automatically called,
when the signal is triggered.
Boost.SmartPoiners TR1 Boost.SmartPoiners offers many smart pointers simplifying the management of
dynamically allocated objects.
Boost.Spirit Boost.Spirit allows generating parsers using a syntax similar to EBNF (Extended
Backus Naur Form).
Boost.StringAlgorithms Boost.StringAlgorithms provides many stand-alone functions to facilitate string
handling.
Boost.System TR2 Boost.System offers a framework to process system- and application-specific error
codes.
Boost.Thread C++0x Boost.Thread allows developing multithreaded applications.

Boost.Tokenizer Boost.Tokenizer allows iterating over the individual components of a string.

Boost.Tuple TR1 Boost.Tuple offers a generalized version of std::pair that allows grouping of any
number of data.
Boost.Unordered TR1 Boost.Unordered enlarges the containers of the C++ standard by adding
boost::unordered_set and boost::unordered_map.
Boost.Variant Boost.Variant permits the definition of data types that, similar to union, group
multiple data types. The advantage of Boost.Variant over union is the possibility to
use classes as well.

While the Technical Report 1 was published in 2003, details about the standardization in regards to C++0x and the
Technical Report 2 illustrate the current status quo. Since neither the next revision of the C++ standard nor the Technical
Report 2 has been approved yet, they may still change in the future.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter2:2:
Chapter Smart
Smart Pointers
Pointers
Chapter 3: Function Objects

Chapter 2: Smart Pointers


Table of Contents 2.1 General
2.2 RAII
2.3 Scoped Pointer
2.4 Scoped Array
2.5 Shared Pointer
2.6 Shared Array
2.7 Weak Pointer
2.8 Intrusive Pointer
2.9 Pointer Container
2.10 Exercises

This book is licensed under a Creative Commons License.

2.1 General

The first version of the C++ standard adapted in 1998 only provides one smart pointer: std::auto_ptr. In principle, it
behaves like a regular pointer: It provides access to a dynamically allocated object by storing its address. However,
std::auto_ptr is considered intelligent and smart since it automatically releases the contained object during destruction by
calling the delete operator. This certainly requires that it is provided with the address of the object - returned by the new
operator - at initialization. Since the delete operator is called within the destructor of std::auto_ptr, the associated memory
for the contained object is guaranteed to be released. This is one advantage of smart pointers.

This becomes even more important in conjunction with exceptions: Without smart pointers such as std::auto_ptr, every
function allocating dynamic memory would be required to catch every possible exception in order to release the memory
prior to passing on the exception to its calling function. The Boost C++ Library Smart Pointers provides many additional
smart pointers that can be used in all kind of situations.

2.2 RAII

The principle of smart pointers is based on a common idiom named RAII: Resource acquisition is initialization. Smart
pointers are only one example for this idiom - certainly a very prominent one. Smart pointers are used to ensure that
dynamically allocated memory is released properly under all circumstances, freeing the developer from the burden of
managing this on her own. This includes scenarios in which execution of a function is interrupted by an exception and the
instruction to release the memory is skipped. This guarantee is accomplished by initializing a smart pointer with the
address of a dynamically allocated object which in turn is used to release the memory during destruction. Since the
destructor is always executed the contained memory is therefore always released.

RAII is applied whenever a second instruction is mandatory in order to release a resource previously allocated by another
instruction. Since many C++ applications require dynamically managed memory, smart pointers are an important RAII
class. RAII itself can be applied in many other scenarios though.

#include <windows.h>
class windows_handle
{
public:
windows_handle(HANDLE h)
: handle_(h)
{
}
~windows_handle()
{
CloseHandle(handle_);
}
HANDLE handle() const
{
return handle_;
}
private:
HANDLE handle_;
};
int main()
{
windows_handle h(OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetCurrentProcessId()));
SetPriorityClass(h.handle(), HIGH_PRIORITY_CLASS);
}

Download source code

The above example defines a class named windows_handle that calls the function CloseHandle() in its destructor. Since it is
a Windows API function, the program can only be executed on Windows. In Windows, many resources are required to be
opened prior to their usage. This implicitly implies that resources should be closed once no longer used. The class
windows_handle provides a mechanism to ensure just that.

An instance of type windows_handle is initialized with a handle. Windows utilizes handles in order to uniquely identify its
resources. For example, the function OpenProcess() returns a handle of type HANDLE that can be used to access a
currently running process. In the code example, the own process is accessed - in other words the application itself.

Using the returned handle, the process priority is increased allowing the application to request more CPU time from the
scheduler. This is only for illustration purposes and does not serve any real benefit though. The important point here is
that the resource opened with OpenProcess() does not need to be explicitly closed using CloseHandle(). Certainly, the
resource is likely to be closed once the application terminates. However, in more complex applications the class
windows_handle ensures that a resource is correctly closed if no longer needed. Once a particular resource leaves its
visibility scope - in the above example of h at the end of the function main() - the destructor is automatically invoked
which in turn closes the contained resource.

2.3 Scoped Pointer

A scoped pointer is a pointer that is the sole owner of a dynamically allocated object. The corresponding class is named
boost::scoped_ptr and is defined in boost/scoped_ptr.hpp. Unlike std::auto_ptr, a scoped pointer is not able to transfer
ownership of its contained object to another scoped pointer. Once initialized with an address, the dynamically allocated
object is released during destruction.

Since a scoped pointer simply stores and solely owns an address, the implementation of boost::scoped_ptr is less complex
than std::auto_ptr. boost::scoped_ptr should be preferred if transfer of ownership is not required. In these situations, it
may be a better choice than std::auto_ptr to avoid inadvertent transfer of ownership.

#include <boost/scoped_ptr.hpp>
int main()
{
boost::scoped_ptr<int> i(new int);
*i = 1;
*i.get() = 2;
i.reset(new int);
}

Download source code

Once initialized, the contained object of the smart pointer boost::scoped_ptr can be accessed through an interface similar
to an ordinary pointer. This is achieved by providing the corresponding operator overloads operator*(), operator->() as
well as operator bool(). In addition, the methods get() and reset() are available. While the former one returns the address
of the contained object, the latter one allows to reinitialize the smart pointer with a new object. In this case, the contained
object is automatically destroyed before the new object is assigned.

The contained object is released using the delete operator within the destructor of boost::scoped_ptr. This puts an
important restriction on the types of objects boost::scoped_ptr can contain. boost:scoped_ptr is not allowed to be
initialized with the address of a dynamically allocated array since this would require a call to the delete[] operator instead.
In these cases, the class boost:scoped_array can be used which is introduced next.

2.4 Scoped Array

A scoped array is used just like a scoped pointer. The crucial difference is that the destructor of the scoped array uses the
delete[] operator to release the contained object. Since this operator only applies to array objects, a scoped array must be
initialized with the address of a dynamically allocated array.
The corresponding class for scoped arrays is boost::scoped_array and is defined in boost/scoped_array.hpp.

#include <boost/scoped_array.hpp>
int main()
{
boost::scoped_array<int> i(new int[2]);
*i.get() = 1;
i[1] = 2;
i.reset(new int[3]);
}

Download source code

The class boost::scoped_array provides overloads for the operator[]() and operator bool() operators. Using operator[](), a
specific element of the array can be accessed - an object of type boost::scoped_array thus behaves exactly like the array it
contains.

Just like boost::scoped_ptr, the methods get() and reset() are provided as well allowing to retrieve and reinitialize the
address of the contained object.

2.5 Shared Pointer

This smart pointer is one of the most utilized and has been badly missed in the first version of the C++ standard. It has
been added to the standard as part of the Technical Report 1 (TR1). If this report is supported by the development
environment used, the class std::shared_ptr defined in memory can be used. Within the Boost C++ library, this smart
pointer is named boost::shared_ptr and is defined in boost/shared_ptr.hpp.

The smart pointer boost::shared_ptr is essentially similar to boost::scoped_ptr. The key difference is that boost::shared_ptr
is not necessarily the exclusive owner of an object. The ownership can be shared with other smart pointers of type
boost::shared_ptr. In these cases, the shared object is not released until the last shared pointer referencing the object is
destroyed.

Since ownership can be shared with boost::shared_ptr, copies of any shared pointer can be created - opposed to
boost::scoped_ptr. This actually allows the usage of smart pointers with the standard containers - something that cannot
be done with std::auto_ptr since it transfers its ownership when copied.

#include <boost/shared_ptr.hpp>
#include <vector>
int main()
{
std::vector<boost::shared_ptr<int> > v;
v.push_back(boost::shared_ptr<int>(new int(1)));
v.push_back(boost::shared_ptr<int>(new int(2)));
}

Download source code


Thanks to boost::shared_ptr, it is possible to safely use dynamically allocated objects with the standard containers as
shown in the above example. Since boost::shared_ptr can share the ownership of its contained object, the copies stored by
the container (as well as the additional copies in case the container needs to be rearranged) are equal. As outlined before,
this is not the case with std::auto_ptr which therefore should never be stored within a container.

Similar to boost::scoped_ptr, the class boost::shared_ptr provides overloads for the following operators: operator*(),
operator->() and operator bool(). In addition, get() and reset() are available as well to retrieve and reinitialize the address
of the contained object.

#include <boost/shared_ptr.hpp>
int main()
{
boost::shared_ptr<int> i1(new int(1));
boost::shared_ptr<int> i2(i1);
i1.reset(new int(2));
}

Download source code

The example defines two shared pointer i1 and i2 which both refer to the same object of type int. While i1 is explicitly
initialized with the address returned by the new operator, i2 is copy-constructed of i1. The address of the contained
integer of i1 is then reinitialized by a call to reset(). The previously contained object however is not released since it is still
referenced by i2. The smart pointer boost::shared_ptr actually counts the number of shared pointers currently referencing
the same object and releases it only once the last shared pointer loses its scope.

By default, boost::shared_ptr uses the delete operator to destroy the contained object. However, the method of destruction
can actually be specified as the following example illustrates:

#include <boost/shared_ptr.hpp>
#include <windows.h>
int main()
{
boost::shared_ptr<void> h(OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetCurrentProcessId()),
CloseHandle);
SetPriorityClass(h.get(), HIGH_PRIORITY_CLASS);
}

Download source code

The constructor of boost::shared_ptr takes a regular function or a function object as the second parameter which in turn is
used for destruction of the contained object. In the given example, the Windows API function CloseHandle() is passed.
Once the variable h loses its scope, the passed function is called instead of the delete operator. In order to avoid compiler
errors, the function is required to take one parameter of type HANDLE which is the case with CloseHandle().
This example actually behaves the same as the one illustrating the RAII idiom earlier in this chapter. However, instead of
defining a separate class windows_handle, the example takes advantage of the specific characteristics of boost::shared_ptr
by passing a method to the constructor which is automatically called once the shared pointer loses its scope.
2.6 Shared Array

A shared array works essentially the same as a shared pointer. The crucial difference is that the destructor of the shared
array uses the delete[] operator by default to release the contained object. Since this operator only applies to array
objects, a shared array must be initialized with the address of a dynamically allocated array.

The corresponding class for shared arrays is boost::shared_array and is defined in boost/shared_array.hpp.

#include <boost/shared_array.hpp>
#include <iostream>
int main()
{
boost::shared_array<int> i1(new int[2]);
boost::shared_array<int> i2(i1);
i1[0] = 1;
std::cout << i2[0] << std::endl;
}

Download source code

Just like with a shared pointer, the ownership of the contained object can be shared with other shared arrays. The example
defines two variables i1 and i2 which both refer to the same dynamically allocated array. The value 1 - stored using the
operator[]() of i1 - can be referenced and e.g. printed to the standard output stream using i2.

As with all the smart pointers introduced in this chapter, boost::shared_array also provides the methods get() and reset().
In addition, the operator bool() is overloaded as well.

2.7 Weak Pointer

Every smart pointer introduced so far can be used individually for different scenarios. In contrast, a weak pointer only
makes sense if used in conjunction with a shared pointer. It is defined as boost::weak_ptr in boost/weak_ptr.hpp

#include <windows.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <iostream>
DWORD WINAPI reset(LPVOID p)
{
boost::shared_ptr<int> *sh = static_cast<boost::shared_ptr<int>*>(p);
sh->reset();
return 0;
}
DWORD WINAPI print(LPVOID p)
{
boost::weak_ptr<int> *w = static_cast<boost::weak_ptr<int>*>(p);
boost::shared_ptr<int> sh = w->lock();
if (sh)
std::cout << *sh << std::endl;
return 0;
}
int main()
{
boost::shared_ptr<int> sh(new int(99));
boost::weak_ptr<int> w(sh);
HANDLE threads[2];
threads[0] = CreateThread(0, 0, reset, &sh, 0, 0);
threads[1] = CreateThread(0, 0, print, &w, 0, 0);
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
}

Download source code

A boost::weak_ptr must always be initialized with a boost::shared_ptr. Once initialized, it basically offers only one useful
method: lock(). It returns a boost::shared_ptr that shares ownership with the shared pointer used to initialize the weak
pointer. In case the shared pointer does not contain any object, the returned one is empty as well.

Weak pointers make sense whenever a function is expected to work with an object managed by a shared pointer, but the
lifetime of the object does not depend on the function itself. The function should only work with the object as long as it is
owned by at least one shared pointer within the program. In case the shared pointer is reset, the object should not be
kept alive due to an additional shared pointer inside the corresponding function.

The above example creates two threads inside main() using functions provided by the Windows API. Thus, the example
only compiles and executes under the Windows platform.

The first thread executes the function reset() that receives the address of a shared pointer. The second thread executes the
function print() which contains the address of a weak pointer. This weak pointer has been previously initialized with the
shared pointer.

Once the application is launched, both reset() and print() are executed at the same time. However, the order of execution
cannot be predicted. This leads to the potential issue of reset() destroying the object while it is being accessed by print()
at the same time.

The weak pointer solves this issue as follows: Invoking lock() returns a shared pointer which points to a valid object in
case it exists at the time of the call. If not, the shared pointer is set to 0 and thus equivalent to a standard null pointer.

The weak pointer itself does not have any impact on the lifetime of an object. In order to safely access the object within
the print() function nonetheless, lock() returns a shared pointer. This guarantees that - even if the object is attempted to
be released by a different thread - it continues to exist thanks to the returned shared pointer.

2.8 Intrusive Pointer

In general, the intrusive pointer works exactly as the shared pointer. However, while boost::shared_ptr internally keeps
track of the number of shared pointers referencing a particular object, the developer has to keep track of this information
for the intrusive pointer. This is particularly helpful for e.g. framework objects that already keep track of the number of
times they are referenced themselves.
The intrusive pointer is defined as boost::intrusive_ptr in boost/intrusive_ptr.hpp.

#include <boost/intrusive_ptr.hpp>
#include <atlbase.h>
#include <iostream>
void intrusive_ptr_add_ref(IDispatch *p)
{
p->AddRef();
}
void intrusive_ptr_release(IDispatch *p)
{
p->Release();
}
void check_windows_folder()
{
CLSID clsid;
CLSIDFromProgID(CComBSTR("Scripting.FileSystemObject"), &clsid);
void *p;
CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, __uuidof(IDispatch), &p);
boost::intrusive_ptr<IDispatch> disp(static_cast<IDispatch*>(p));
CComDispatchDriver dd(disp.get());
CComVariant arg("C:\\Windows");
CComVariant ret(false);
dd.Invoke1(CComBSTR("FolderExists"), &arg, &ret);
std::cout << (ret.boolVal != 0) << std::endl;
}
void main()
{
CoInitialize(0);
check_windows_folder();
CoUninitialize();
}

Download source code

The above example uses functions provided by COM (Component Object Model) thus, only builds and executes under the
Windows platform. COM objects are a perfect example for boost::intrusive_ptr since they keep track of the number of
pointers referencing them. The internal reference count can be incremented or decremented by 1 using the AddRef() or
Release() method respectively. Once the counter reaches 0, the COM object is automatically destroyed.

The two methods AddRef() and Release() are called from within the intrusive_ptr_add_ref() and intrusive_ptr_release()
functions to increment and decrement the internal reference counter of the corresponding COM object. The COM object
used in this example is named 'FileSystemObject' and is available in Windows by default. It allows access to the underlying
file system to e.g. verify whether or not a given directory exists. In the above example, the existence of a directory named
C:\Windows is checked. How that works internally depends solely on COM and is irrelevant in regards to the functionality
of boost::intrusive_ptr. The crucial point is that once the intrusive pointer disp loses its scope at the end of the
check_windows_folder() function, the function intrusive_ptr_release() is going to be automatically called. This in turn will
decrement the internal reference counter of the COM object 'FileSystemObject' to 0 and thus destroy the object.
2.9 Pointer Container

After meeting the different smart pointers of the Boost C++ Libraries, one should be able to write safe code for
dynamically allocated objects as well as arrays. Many times, these objects are required to be stored within a container
which - as seen above - is fairly easy using boost::shared_ptr and boost::shared_array.

#include <boost/shared_ptr.hpp>
#include <vector>
int main()
{
std::vector<boost::shared_ptr<int> > v;
v.push_back(boost::shared_ptr<int>(new int(1)));
v.push_back(boost::shared_ptr<int>(new int(2)));
}

Download source code

While the code in the above example is absolutely correct and smart pointers can be used the given way, it is actually
impractical for a couple of reasons. For once, the repetitive declaration of boost::shared_ptr requires more typing. In
addition, copying the boost::shared_ptr to, from or within the container requires incrementing and decrementing the
internal reference count constantly and thus is deemed very inefficient. For these reasons, the Boost C++ Libraries provide
Pointer Container that are specialized for the management of dynamically allocated objects.

#include <boost/ptr_container/ptr_vector.hpp>
int main()
{
boost::ptr_vector<int> v;
v.push_back(new int(1));
v.push_back(new int(2));
}

Download source code

The class boost::ptr_vector defined in boost/ptr_container/ptr_vector.hpp works the same way as the container used and
initialized with the boost::shared_ptr template parameter in the previous example. Since boost::ptr_vector is specialized
for dynamically allocated objects, it is easier and more efficient to use though. However, as boost::ptr_vector is the solely
owner of all contained objects, the ownership cannot be shared with a shared pointer not stored inside the container
opposed to using std::vector<boost::shared_ptr<int> >.

Besides boost::ptr_vector, additional containers specialized for managing dynamically allocated objects are available
including boost::ptr_deque, boost::ptr_list, boost::ptr_set, boost::ptr_map, boost::ptr_unordered_set and
boost::ptr_unordered_map. These containers are equivalent to the ones provided by the C++ standard. The last two
containers match the std::unordered_set and std::unordered_map containers added to the C++ standard as part of the
Technical Report 1. They are also implemented as boost::unordered_set and boost::unordered_map by the Boost C++
Libraries that can be utilized if the used implementation of the C++ Standard does not support the Technical Report 1.
2.10 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Optimize the following program by using an appropriate smart pointer:

#include <iostream>
#include <cstring>
char *get(const char *s)
{
int size = std::strlen(s);
char *text = new char[size + 1];
std::strncpy(text, s, size + 1);
return text;
}
void print(char *text)
{
std::cout << text << std::endl;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cerr << argv[0] << " <data>" << std::endl;
return 1;
}
char *text = get(argv[1]);
print(text);
delete[] text;
}

Download source code

2. Optimize the following program:

#include <vector>
template <typename T>
T *create()
{
return new T;
}
int main()
{
std::vector<int*> v;
v.push_back(create<int>());
}

Download source code

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter3:3:
Chapter Function
Function Objects
Objects
Chapter 4: Event Handling

Chapter 3: Function Objects


Table of Contents 3.1 General
3.2 Boost.Bind
3.3 Boost.Ref
3.4 Boost.Function
3.5 Boost.Lambda
3.6 Exercises

This book is licensed under a Creative Commons License.

3.1 General

This chapter, which deals with function objects, could have easily been named 'Functions of higher order' as well. This
actually refers to functions that can be passed to or returned from other functions. Functions of higher order are
implemented as function objects in C++ thus, the original title still makes sense.

Throughout this chapter, several Boost C++ Libraries dealing with function objects are presented. While Boost.Bind replaces
the well-known std::bind1st() and std::bind2nd() functions from the C++ standard, Boost.Function provides a class to
encapsulate function pointers. Finally, Boost.Lambda introduces a way of creating anonymous functions.

3.2 Boost.Bind

Boost.Bind is a library simplifying a mechanism already provided by the C++ standard using the std::bind1st() and
std::bind2nd() template functions: The usage of functions with a virtually unlimited number of parameters in scenarios
expecting functions with a specific signature. One of the best examples for such a scenario is the many different algorithms
defined by the C++ standard.

#include <iostream>
#include <vector>
#include <algorithm>
void print(int i)
{
std::cout << i << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), print);
}

Download source code

For its third parameter, the algorithm std::for_each() expects a function or function object taking exactly one parameter. If
std::for_each() is executed, all elements of the particular container - in the above example of type int - are sequentially
passed to the print() function. However, if a function with a different signature should be used, things are getting
complicated. For example, imagine if the following function add(), adding up a constant value to each element of the
container and displaying the result, should be passed instead.

void add(int i, int j)


{
std::cout << i + j << std::endl;
}

Since std::for_each() expects a function taking one parameter only, the add() function cannot be passed directly. Instead,
the source code needs to be modified.

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
class add
: public std::binary_function<int, int, void>
{
public:
void operator()(int i, int j) const
{
std::cout << i + j << std::endl;
}
};
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), std::bind1st(add(), 10));
}

Download source code

The above application adds up the value 10 to every element of the container v and displays the result using the standard
output stream. The source code had to be substantially modified in order to allow for this though: The add() function has
been converted to a function object derived from std::binary_function.

Boost.Bind simplifies the binding between different functions. It consists of the boost::bind() template function only and is
defined in boost/bind.hpp. This function allows to implement the above example as follows:

#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
void add(int i, int j)
{
std::cout << i + j << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1));
}

Download source code

Functions like add() do not need to be converted to a function object any longer in order to be used with std::for_each().
Using boost::bind(), the function can be used as is by passing it as the first parameter.

Since the add() function expects two parameters, they need to be passed to boost::bind() as well. The first one is the
constant value 10, the second one is a weird looking _1.

_1 is called a placeholder and is defined in Boost.Bind. Besides _1, Boost.Bind also defines _2 and _3. Using these
placeholders, boost::bind() can be transformed into an unary, binary or tertiary function. In the case of _1, boost::bind()
is transformed into an unary function - a function expecting a single parameter. This is necessary since std::for_each()
expects such an unary function as its third parameter.

Once the application is executed, std::for_each() calls the unary function for each element of the container v. The element
value is passed to the unary function using the placeholder _1. The placeholder as well as the constant value are being
further passed to the add() function. Using this mechanism, std::for_each() only sees the unary function defined by
boost::bind(). boost::bind() itself simply calls a different function and passes items such as a constant value or
placeholders as parameters.

The following example defines a binary function by means of boost::bind() which is utilized with the std::sort() algorithm
which expects a binary function as its third parameter.

#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
bool compare(int i, int j)
{
return i > j;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2));
}

Download source code

Due to the usage of the two placeholders _1 and _2, boost::bind() defines a binary function. The std::sort() algorithm
calls this function with two elements from the container v and uses the return value to sort the container accordingly.
Based on the definition of the compare() function, the container is sorted in descending order.

However, since compare() already is a binary function, the usage of boost::bind() is actually superfluous.

#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
bool compare(int i, int j)
{
return i > j;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::sort(v.begin(), v.end(), compare);
}

Download source code

The usage of boost::bind() can still make sense though. For example, in case the container should be sorted in ascending
order without changing the definition of the compare() function.

#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
bool compare(int i, int j)
{
return i > j;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1));
}

Download source code

This example only changed the order of the placeholders: _2 is passed as the first parameter while _1 is passed as the
second parameter to compare() which effectively changes the sorting order.

3.3 Boost.Ref

The library Boost.Ref is typically used in conjunction with Boost.Bind and thus is presented next. It provides two functions -
boost::ref() and boost::cref() - defined in boost/ref.hpp.

Boost.Ref is of importance whenever functions containing at least one reference parameter should be used with
boost::bind(). Since boost::bind() copies its parameters, references need to be handled separately.

#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
void add(int i, int j, std::ostream &os)
{
os << i + j << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1, boost::ref(std::cout)));
}

Download source code

The above example uses the known add() function from the previous paragraph. This time however, the function expects a
reference to a stream object in order to print the information. Since parameters to boost::bind() are passed by value,
std::cout cannot be used directly since otherwise the function would attempt to create a copy of it.

Using the template function boost::ref(), streams such as std::cout can be passed by reference which allows to compile
the example successfully.
In order to pass constant objects by reference, the template function boost::cref() can be used instead.

3.4 Boost.Function

For encapsulating function pointers, Boost.Function provides a class named boost::function. It is defined in
boost/function.hpp and is used as follows:

#include <boost/function.hpp>
#include <iostream>
#include <cstdlib>
#include <cstring>
int main()
{
boost::function<int (const char*)> f = std::atoi;
std::cout << f("1609") << std::endl;
f = std::strlen;
std::cout << f("1609") << std::endl;
}

Download source code

boost::function allows to define a pointer to a function with a specific signature. The above example defines a pointer f that
can point to functions expecting a parameter of type const char* and returning a value of type int. Once defined, functions
with matching signatures can then be assigned to the pointer accordingly. The example program first assigns the
std::atoi() function to f before it is reassigned to std::strlen().

Note though that the given data types do not necessarily need to match exactly: Even though std::strlen() uses std::size_t
as its return type, it still can be assigned to f.

Since f is a function pointer, the assigned function can be called using the overloaded operator()() operator. Depending on
what function is currently assigned, either std::atoi() or std::strlen() is called in the given example.

If f is called without having a function assigned, a boost::bad_function_call exception is thrown.

#include <boost/function.hpp>
#include <iostream>
int main()
{
try
{
boost::function<int (const char*)> f;
f("");
}
catch (boost::bad_function_call &ex)
{
std::cout << ex.what() << std::endl;
}
}
Download source code

Note that assigning the value 0 to a function pointer of type boost::function will release any currently assigned function.
Calling it after releasing will also result in a boost::bad_function_call exception being thrown. In order to check whether or
not a function pointer currently is assigned to a function, the empty() function or the operator bool() operator can be used.

Using Boost.Function, class member functions can also be assigned to objects of type boost::function.

#include <boost/function.hpp>
#include <iostream>
struct world
{
void hello(std::ostream &os)
{
os << "Hello, world!" << std::endl;
}
};
int main()
{
boost::function<void (world*, std::ostream&)> f = &world::hello;
world w;
f(&w, boost::ref(std::cout));
}

Download source code

When calling such a function, the first parameter passed indicates the particular object for which the function is called.
Therefore, the first parameter after the open parenthesis inside the template definition must be a pointer to that particular
class. The following parameters then denote the signature of the corresponding member function.

The application also utilizes boost::ref() from the Boost.Ref library which provides an easy mechanism of passing
references to Boost.Function.

3.5 Boost.Lambda

Unnamed functions - called lambda functions - currently do exist in various programming languages but C++. With the
help of the Boost.Lambda library however, they can now be used in C++ applications as well.
The general goal of lambda functions is to make the source code more compact and thus more comprehensible. Take the
code sample from the first paragraph of this chapter for example.

#include <iostream>
#include <vector>
#include <algorithm>
void print(int i)
{
std::cout << i << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), print);
}

Download source code

This program takes the elements of the container v and writes them to the standard output stream using the print()
function. Since print() only writes a simple int, the implementation of the function is fairly simple. Strictly speaking, it is so
simple that it would be convenient if one could simply define it within the std::for_each() algorithm directly; thus saving
the need for an additional function. The additional benefit is a more compact code since the algorithm and the function for
the data output are not locally separated. Boost.Lambda actually makes this a reality.

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(), std::cout << boost::lambda::_1 << "\n");
}

Download source code

Boost.Lambda provides several constructs to define unnamed functions. Code is placed where executed thus skipping the
overhead of enclosing it in a function and the corresponding function call. As with the original example, the program writes
all elements of the container v to the standard output stream.

Similar to Boost.Bind, Boost.Lambda also defines three placeholders named _1, _2 and _3. Unlike Boost.Bind, these
placeholders are defined in a separate namespace though. Hence, the first placeholder in the example is referenced via
boost::lambda::_1. In order to satisfy the compiler, the corresponding header file boost/lambda/lambda.hpp needs to be
included.

Even though the position of the code being the third parameter to std::for_each() seems odd, Boost.Lambda allows for
writing regular C++ code. Using the placeholder, the elements of the container f can be passed to std::cout via << in
order to write them to the standard output stream.

While Boost.Lambda is quite powerful, there are some drawbacks. To insert a line break into the output of the above
example, "\n" must be used instead of std::endl in order to successfully compile. Since the type expected by the unary
std::endl template function is different from the one of the lambda function std::cout << boost::lambda::_1, it cannot be
used in this case.

The next revision of the C++ standard will likely add lambda functions as an integral part to the C++ language itself thus
eliminating the need for a separate library. It may still take years though before the next revision is published and widely
adopted by the different compiler manufacturers. Until then, Boost.Lambda proves to be a perfect replacement as can be
seen in the following example which only writes elements greater than 1 to the standard output stream.

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/if.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);
std::for_each(v.begin(), v.end(),
boost::lambda::if_then(boost::lambda::_1 > 1,
std::cout << boost::lambda::_1 << "\n"));
}

Download source code

The header file boost/lambda/if.hpp defines several constructs to allow if statements within lambda functions. The most
basic construct is the boost::lambda::if_then() template function that expects two parameters: The first parameter
evaluates a condition - if true, the second parameter is executed. Each parameter can be a lambda function itself as shown
in the example.

Besides boost::lambda::if_then(), Boost.Lambda provides the boost::lambda::if_then_else() and


boost::lambda::if_then_else_return() template functions - each expecting three parameters. Additional template functions
for loops, cast operators and even for throw - allowing lambda functions to throw exceptions - are provided as well.

Even though complex lambda functions in C++ can be built utilizing these template functions, one has to consider aspects
such as readability as well as maintainability. Since one needs to learn and understand additional functions like
boost::lambda::if_then() instead of using the known C++ keywords if and else, the benefit of lambda functions usually
decreases with their complexity. Most of the time, it is more reasonable to define a discrete function using the familiar
C++ constructs instead.

3.6 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Simplify the following application by converting the function object divide_by to a function and by replacing the for
loop used to output the data with a standard C++ algorithm:
#include <algorithm>
#include <functional>
#include <vector>
#include <iostream>
class divide_by
: public std::binary_function<int, int, int>
{
public:
int operator()(int n, int div) const
{
return n / div;
}
};
int main()
{
std::vector<int> numbers;
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
std::transform(numbers.begin(), numbers.end(), numbers.begin(), std::bind2nd(divide_by(), 2));
for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
std::cout << *it << std::endl;
}

Download source code

2. Simplify the following application by replacing both for loops with standard C++ algorithms:

#include <string>
#include <vector>
#include <iostream>
int main()
{
std::vector<std::string> strings;
strings.push_back("Boost");
strings.push_back("C++");
strings.push_back("Libraries");
std::vector<int> sizes;
for (std::vector<std::string>::iterator it = strings.begin(); it != strings.end(); ++it)
sizes.push_back(it->size());
for (std::vector<int>::iterator it = sizes.begin(); it != sizes.end(); ++it)
std::cout << *it << std::endl;
}

Download source code

3. Simplify the following application by modifying the type of the variable processors and replacing the for loop with a
standard C++ algorithm:

#include <vector>
#include <iostream>
#include <cstdlib>
#include <cstring>
int main()
{
std::vector<int(*)(const char*)> processors;
processors.push_back(std::atoi);
processors.push_back(reinterpret_cast<int(*)(const char*)>(std::strlen));
const char data[] = "1.23";
for (std::vector<int(*)(const char*)>::iterator it = processors.begin(); it != processors.end(); ++it)
std::cout << (*it)(data) << std::endl;
}

Download source code

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter4:4:
Chapter Event
Event Handling
Handling
Chapter 5: String Handling

Chapter 4: Event Handling


Table of Contents 4.1 General
4.2 Signals
4.3 Connections
4.4 Exercises

This book is licensed under a Creative Commons License.

4.1 General

Many developers think about graphical user interfaces when hearing the term 'event handling': At the click of a button, the
associated function is executed. The click itself is the event while the function is the corresponding event handler.

The usage of this pattern is certainly not limited to graphical user interfaces though. In general, arbitrary objects can call
dedicated functions based on specific events. The Boost.Signals library introduced in this chapter provides an easy way to
apply this pattern in C++.

Strictly speaking, the Boost.Function library could also be used for event handling. One crucial difference between
Boost.Function and Boost.Signals, however, is the ability of Boost.Signals to associate more than one event handler with a
single event. Therefore, Boost.Signals supports event-driven development much better and should be the first choice
whenever events must be handled.

4.2 Signals

While the name of the library seems to be a bit misleading at first, it actually is not. Boost.Signals implements a pattern
named signal to slot which is based on the concept that associated slots are executed once the corresponding signal is
issued. In principle, one can substitute the words 'signal' and 'slot' with 'event' and 'event handler', respectively. However,
since signals can be issued at any given time, the concept renounces events.

Consequently, Boost.Signals does not offer classes that resemble events. Instead, it provides a class named boost::signal
defined in boost/signal.hpp. This header file is actually the only one required knowing since it will include dependent
header files automatically.

Boost.Signals defines additional classes residing in the boost::signals namespace. Since boost::signal is the most commonly
used class, it actually resides in the namespace boost instead.
#include <boost/signal.hpp>
#include <iostream>
void func()
{
std::cout << "Hello, world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
s.connect(func);
s();
}

Download source code

boost::signal is actually implemented as a template function expecting the signature of a function, used as the event
handler, as its template parameter. In the example, only functions with a signature of void () can be associated with the
signal s successfully.

The function func() is associated with the signal s using the connect() method. Since func() conforms to the required void
() signature, the association is successfully established. func() is therefore called whenever the signal s is triggered.

The signal is triggered by calling s just like a regular function. The signature of this function corresponds to the one passed
as the template parameter: The brackets are empty since void () does not expect any parameters.

Calling s results in a trigger which in turn executes the func() function - previously associated using connect() - accordingly.

The same example can also be realized using Boost.Function instead.

#include <boost/function.hpp>
#include <iostream>
void func()
{
std::cout << "Hello, world!" << std::endl;
}
int main()
{
boost::function<void ()> f;
f = func;
f();
}

Download source code

Similar to the previous example, func() is associated with f. Once called, func() is executed accordingly. While
Boost.Function is limited to these scenarios, Boost.Signals offers far more variety such as associating multiple functions
with a particular signal as shown in the following example.

#include <boost/signal.hpp>
#include <iostream>
void func1()
{
std::cout << "Hello" << std::flush;
}
void func2()
{
std::cout << ", world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
s.connect(func1);
s.connect(func2);
s();
}

Download source code

boost::signal allows assigning multiple functions to a particular signal by calling the connect() method repeatedly.
Whenever the signal is triggered, the functions are executed in the order they have been previously associated using
connect().

Alternatively, the order can be explicitly specified using an overloaded version of the connect() method that expects a value
of type int as an additional parameter.

#include <boost/signal.hpp>
#include <iostream>
void func1()
{
std::cout << "Hello" << std::flush;
}
void func2()
{
std::cout << ", world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
s.connect(1, func2);
s.connect(0, func1);
s();
}

Download source code

As with the previous example, func1() is executed before func2().

To release an associated function with a given signal, the disconnect() method is used.
#include <boost/signal.hpp>
#include <iostream>
void func1()
{
std::cout << "Hello" << std::endl;
}
void func2()
{
std::cout << ", world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
s.connect(func1);
s.connect(func2);
s.disconnect(func2);
s();
}

Download source code

This example only prints Hello since the association with func2() has been released prior to triggering the signal.

Besides connect() and disconnect(), boost::signal offers only a few additional methods.

#include <boost/signal.hpp>
#include <iostream>
void func1()
{
std::cout << "Hello" << std::flush;
}
void func2()
{
std::cout << ", world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
s.connect(func1);
s.connect(func2);
std::cout << s.num_slots() << std::endl;
if (!s.empty())
s();
s.disconnect_all_slots();
}

Download source code

num_slots() returns the number of associated functions. If no function is associated, num_slots() returns 0 accordingly. In
this particular case, the empty() method can be used instead. The disconnect_all_slots() method actually does exactly what
its name expresses: It releases all existing associations.

After seeing how functions are associated with signals as well as understanding what happens once a signal is triggered,
one question actually remains: What happens to the return values of these functions? The following example answers this
question.

#include <boost/signal.hpp>
#include <iostream>
int func1()
{
return 1;
}
int func2()
{
return 2;
}
int main()
{
boost::signal<int ()> s;
s.connect(func1);
s.connect(func2);
std::cout << s() << std::endl;
}

Download source code

Both func1() and func2() now have a return value of type int. s processes both return values and writes them to the
standard output stream somehow. However, what happens exactly?

The above example will actually write 2 to the standard output stream. Both return values were correctly accepted by s but
were ignored except for the last one. By default, only the last return value of all associated functions is actually returned.

It is possible to customize a signal so that the individual return values are processed accordingly. For that purpose, a so-
called combiner must be passed to boost::signal as the second parameter.

#include <boost/signal.hpp>
#include <iostream>
#include <algorithm>
int func1()
{
return 1;
}
int func2()
{
return 2;
}
template <typename T>
struct min_element
{
typedef T result_type;
template <typename InputIterator>
T operator()(InputIterator first, InputIterator last) const
{
return *std::min_element(first, last);
}
};
int main()
{
boost::signal<int (), min_element<int> > s;
s.connect(func1);
s.connect(func2);
std::cout << s() << std::endl;
}

Download source code

A combiner is a class overloading the operator()() operator. This operator is automatically called with two iterators pointing
to all return values for a particular signal. The example uses the standard C++ algorithm std::min_element() to determine
and return the smallest value.

Unfortunately, it is not possible to pass an algorithm such as std::min_element() directly to boost::signal as a template
parameter. boost::signal expects that the combiner defines a type called result_type that denotes the type of the value
returned by the operator()() operator. Since this type is omitted by the standard C++ algorithms, an error is issued during
compilation accordingly.

Instead analyzing return values, a combiner can also save them.

#include <boost/signal.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
int func1()
{
return 1;
}
int func2()
{
return 2;
}
template <typename T>
struct min_element
{
typedef T result_type;
template <typename InputIterator>
T operator()(InputIterator first, InputIterator last) const
{
return T(first, last);
}
};
int main()
{
boost::signal<int (), min_element<std::vector<int> > > s;
s.connect(func1);
s.connect(func2);
std::vector<int> v = s();
std::cout << *std::min_element(v.begin(), v.end()) << std::endl;
}

Download source code

The example saves all the return values in a vector which in turn is returned by s().

4.3 Connections

Functions can be managed with the aid of the connect() and disconnect() methods provided by boost::signal. Due to
connect() returning a value of type boost::signals::connection, they can be managed differently as well.

#include <boost/signal.hpp>
#include <iostream>
void func()
{
std::cout << "Hello, world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
boost::signals::connection c = s.connect(func);
s();
c.disconnect();
}

Download source code

The disconnect() method of boost::signal requires a function pointer being passed which can be avoided by calling the
disconnect() method on the boost::signals::connection object directly.

In addition to the disconnect() method, boost::signals::connection also provides methods such as block() and unblock().

#include <boost/signal.hpp>
#include <iostream>
void func()
{
std::cout << "Hello, world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
boost::signals::connection c = s.connect(func);
c.block();
s();
c.unblock();
s();
}

Download source code

The above program executes func() exactly once. Even though the signal s is triggered twice, func() is not called for the
first trigger since the connection c has actually been blocked by a call to block(). Since unblock() is called before the
second trigger, func() is now executed correctly.

Besides boost::signals::connection, a class named boost::signals::scoped_connection is offered that releases the connection
during destruction automatically.

#include <boost/signal.hpp>
#include <iostream>
void func()
{
std::cout << "Hello, world!" << std::endl;
}
int main()
{
boost::signal<void ()> s;
{
boost::signals::scoped_connection c = s.connect(func);
}
s();
}

Download source code

Since the connection object c is destroyed before the signal is triggered, func() is not being called.

boost::signals::scoped_connection is actually derived from boost::signals::connection and thus offers the same methods.
The only difference is the automatic release of the connection during destruction of boost::signals::scoped_connection.

While boost::signals::scoped_connection certainly makes it easier to automatically release connections, objects of this type
still need to be managed. It would be nice if connections could be automatically released in other cases as well without
having the need to actually manage these objects.

#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <memory>
class world
{
public:
void hello() const
{
std::cout << "Hello, world!" << std::endl;
}
};
int main()
{
boost::signal<void ()> s;
{
std::auto_ptr<world> w(new world());
s.connect(boost::bind(&world::hello, w.get()));
}
std::cout << s.num_slots() << std::endl;
s();
}

Download source code

The above program associates the method of an object with a signal by using Boost.Bind. The object is destroyed before
the signal is triggered which creates an issue. Opposed to passing the actual object w, only a pointer has been passed to
boost::bind() instead. By the time s() is actually called, the object referenced by the pointer does no longer exist.

It is possible to modify the program so that the connection is automatically released once the object w is destroyed.

#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <memory>
class world :
public boost::signals::trackable
{
public:
void hello() const
{
std::cout << "Hello, world!" << std::endl;
}
};
int main()
{
boost::signal<void ()> s;
{
std::auto_ptr<world> w(new world());
s.connect(boost::bind(&world::hello, w.get()));
}
std::cout << s.num_slots() << std::endl;
s();
}

Download source code

If executed now, num_slots() actually returns 0 to make sure that no method is tried to be called on an already destroyed
object. The only change necessary was to derive the world class from boost::signals::trackable. Whenever pointers to
objects instead of object copies are used to associate functions with signals, boost::signals::trackable can simplify the
management of the connections considerably.
4.4 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Create a program by defining a class named button which represents a clickable button within a graphical user
interface. Add two methods add_handler() and remove_handler(), both expecting a function name as a parameter, to
the class. If a click() method is called, the registered functions should be executed sequentially.

Test your code by creating an instance of the button class and writing a message to the standard output stream from
within the event handler. Call the click() function to simulate a mouse click on the button.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter5:5:
Chapter String
String Handling
Handling
Chapter 6: Multithreading

Chapter 5: String Handling


Table of Contents 5.1 General
5.2 Locales
5.3 Boost.StringAlgorithms
5.4 Boost.Regex
5.5 Boost.Tokenizer
5.6 Boost.Format
5.7 Exercises

This book is licensed under a Creative Commons License.

5.1 General

Strings in the C++ standard are handled by the std::string class which offers many functions for manipulating them.
Among these are functions searching a string for a specific character or functions returning a substring. Even though
std::string provides more than 100 functions, which makes it one of the more bloated classes of the C++ standard, many
developers still miss additional functionality throughout their daily routine. For example, while Java and .NET provide
functions to convert a string to uppercase, there is no equivalent available in std::string. The Boost C++ Libraries
presented in this chapter try to close this gap.

5.2 Locales

Before the Boost C++ Libraries are introduced though, one should at least take a brief look at locales. Many functions
outlined in this chapter will expect a locale as an additional parameter.

Locales are used in the C++ standard to encapsulate cultural conventions such as the currency symbol, date and time
formats, the symbol used to separate the integer portion of a number from the fractional one (radix character) as well as
the symbol used for grouping numbers with more than three digits (thousands separator).

In terms of string handling, the locale is relevant for describing the order and the individual letters used in the particular
culture. For instance, whether an alphabet contains mutated vowels and what place they take in the alphabet depends on
the culture.

If a function is called that converts a given string to uppercase, the individual steps taken depend on the particular locale.
In the German language, it is obvious that the letter '' is converted to ''; however, this does not necessarily hold true for
other cultures as well.

When working with std::string, the usage of locales can be neglected since none of the functions is dependent on a
particular culture. In order to work with the Boost C++ Libraries in this chapter though, this knowledge is mandatory.

The C++ standard defines a class named std::locale in locale. Every C++ program automatically has one instance of this
class - the global locale which cannot be directly accessed. Instead, a separate object of std::locale must be created via
the default constructor that will be initialized with the same properties as the global locale.

#include <locale>
#include <iostream>
int main()
{
std::locale loc;
std::cout << loc.name() << std::endl;
}

Download source code

The above program will output C on the standard output stream which is the name of the classic locale. This locale
contains descriptions used by default in programs developed with the C language.

This also happens to be the default global locale for every C++ application. It contains descriptions used by the American
culture. For example, the dollar sign is used as the currency symbol, the radix character is a period, and displaying a date
causes the month to be written in English.

The global locale can be changed using the static function global() of the std::locale class.

#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::locale loc;
std::cout << loc.name() << std::endl;
}

Download source code

The static global() function expects a new object of type std::locale as its sole parameter. Using a different constructor of
the class, expecting a character string of type const char*, a locale object for a particular culture can be created. However,
names of locales are not standardized except for the C locale which is named "C" correspondingly. It therefore depends on
the individual C++ standard library which names are actually accepted. In case of Visual Studio 2008, the definitions for
the German culture can be selected using the language string "German" as outlined in the documentation of language
strings.

The program will output German_Germany.1252 if executed. Specifying "German" as the language string selects the definitions
for the German primary language and sublanguage as well as the character map 1252.
In case the sublanguage should be set to a different location of the German culture such as the Swiss, a different language
string can be used.

#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German_Switzerland"));
std::locale loc;
std::cout << loc.name() << std::endl;
}

Download source code

Now, the program will output German_Switzerland.1252 instead.

After getting an understanding about locales in general and how the global one can be changed, the following example
shows how locales affect string handling.

#include <locale>
#include <iostream>
#include <cstring>
int main()
{
std::cout << std::strcoll("", "z") << std::endl;
std::locale::global(std::locale("German"));
std::cout << std::strcoll("", "z") << std::endl;
}

Download source code

The example uses the std::strcoll() function defined in cstring to compare whether the first string is lexicographically less
than the second one. In other words, which of the two strings would be found first in a dictionary.

If executed, the result is both 1 and -1 . Even though the function is called with the same input parameters, the results are
different. The reason is quite simple - while calling std::strcoll() the first time, the global C locale is used. However, when
called the second time, the global locale has been changed to incorporate definitions for the German culture instead. The
order of the two characters '' and 'z' is different for these locales as indicated by the output.

Numerous C functions as well as C++ streams access locales. Albeit functions of the std::string class work independently
from locales, many of the functions outlined in the following paragraphs do not. Hence, locales are met again several times
throughout this chapter.

5.3 Boost.StringAlgorithms

The Boost C++ library Boost.StringAlgorithms provides many stand-alone functions for string manipulation. Strings can be
of type std::string, std::wstring or any different instance of the template class std::basic_string.
The functions are categorized within different header files. For example, functions converting from uppercase to lowercase
are defined in boost/algorithm/string/case_conv.hpp. Since Boost.StringAlgorithms consists of more than 20 different
categories and as many header files, boost/algorithm/string.hpp acts as the common header including all other header files
for convenience. All of the following examples will use this combined header.

As mentioned in the previous paragraph, many functions of the Boost.StringAlgorithms library expect an object of type
std::locale as an additional parameter. However, this parameter is optional - if not provided, the default global locale is
used.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
#include <clocale>
int main()
{
std::setlocale(LC_ALL, "German");
std::string s = "Boris Schling";
std::cout << boost::algorithm::to_upper_copy(s) << std::endl;
std::cout << boost::algorithm::to_upper_copy(s, std::locale("German")) << std::endl;
}

Download source code

The boost::algorithm::to_upper_copy() function is used to convert a string to uppercase. Naturally, there also exists a
function doing the opposite: boost::algorithm::to_lower_copy() converts a string to lowercase. Both functions return the
converted string as result. If the passed string itself should be converted, the functions boost::algorithm::to_upper() or
boost::algorithm::to_lower() can be used instead.

The above example converts the string "Boris Schling" to uppercase using boost::algorithm::to_upper_copy(). The first
call uses the default global locale while the second call explicitly states the locale for the German culture.

Using the latter certainly will result in a correctly converted string since the corresponding uppercase character '' exists for
the lowercase ''. For the C locale instead, '' is an unknown character and thus is not converted. To yield correct results,
either pass the correct locale explicitly or modify the global locale before calling boost::algorithm::to_upper_copy().

Note, that the program uses std::setlocale() - defined in clocale - to set the locale for any C function. Internally, std::cout
uses C functions to display information on the screen. By setting the correct locale, mutated vowels such as '' and '' are
displayed correctly.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::to_upper_copy(s) << std::endl;
std::cout << boost::algorithm::to_upper_copy(s, std::locale("German")) << std::endl;
}
Download source code

The above program sets the German culture for the global locale which causes the first call to
boost::algorithm::to_upper_copy() to use the corresponding definitions for converting '' to ''.
Please note that the std::setlocale() is not called in this example. By setting the global locale using the std::locale::global()
function, the C locale is automatically set as well. In practice, C++ programs almost always set the global locale using
std::locale::global() rather than using std::setlocale() as seen in the previous example.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::erase_first_copy(s, "i") << std::endl;
std::cout << boost::algorithm::erase_nth_copy(s, "i", 0) << std::endl;
std::cout << boost::algorithm::erase_last_copy(s, "i") << std::endl;
std::cout << boost::algorithm::erase_all_copy(s, "i") << std::endl;
std::cout << boost::algorithm::erase_head_copy(s, 5) << std::endl;
std::cout << boost::algorithm::erase_tail_copy(s, 8) << std::endl;
}

Download source code

Boost.StringAlgorithms provides several functions to delete individual characters from a string. How and where the deletion
should occur can be explicitly specified. For example, a particular character can be removed from the complete string by
using boost::algorithm::erase_all_copy(). If only the first occurrence of the character should be removed,
boost::algorithm::erase_first_copy() ought to be used instead. To shorten the string by a specific number of characters on
either end, the functions boost::algorithm::erase_head_copy() and boost::algorithm::erase_tail_copy() can be used
accordingly.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::iterator_range<std::string::iterator> r = boost::algorithm::find_first(s, "Boris");
std::cout << r << std::endl;
r = boost::algorithm::find_first(s, "xyz");
std::cout << r << std::endl;
}

Download source code

Different functions such as boost::algorithm::find_first(), boost::algorithm::find_last(), boost::algorithm::find_nth(),


boost::algorithm::find_head() and boost::algorithm::find_tail() are available to find strings within strings.
All of these functions have in common that they return a pair of iterators of type boost::iterator_range. This class
originates from the Boost C++ Library Boost.Range which defines a range concept based on the iterator concept. Since the
<< operator is overloaded for boost::iterator_range, the result of the individual search algorithm can be directly written to
the standard output stream. The above program prints Boris for the first result and an empty string for the second one.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
#include <vector>
int main()
{
std::locale::global(std::locale("German"));
std::vector<std::string> v;
v.push_back("Boris");
v.push_back("Schling");
std::cout << boost::algorithm::join(v, " ") << std::endl;
}

Download source code

A container of strings is passed as the first parameter to the boost::algorithm::join() function which concatenates them
separated by the second parameter. The example will output Boris Schling accordingly.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::replace_first_copy(s, "B", "D") << std::endl;
std::cout << boost::algorithm::replace_nth_copy(s, "B", 0, "D") << std::endl;
std::cout << boost::algorithm::replace_last_copy(s, "B", "D") << std::endl;
std::cout << boost::algorithm::replace_all_copy(s, "B", "D") << std::endl;
std::cout << boost::algorithm::replace_head_copy(s, 5, "Doris") << std::endl;
std::cout << boost::algorithm::replace_tail_copy(s, 8, "Becker") << std::endl;
}

Download source code

Just like functions for searching strings or removing characters from a string, Boost.StringAlgorithms also provides
functions for replacing a substring within a string. Among these functions are boost::algorithm::replace_first_copy(),
boost::algorithm::replace_nth_copy(), boost::algorithm::replace_last_copy(), boost::algorithm::replace_all_copy(),
boost::algorithm::replace_head_copy() and boost::algorithm::replace_tail_copy(). They can be applied the same way as
the functions used for searching and removing except that they expect an additional parameter - the replacement string.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "\t Boris Schling \t";
std::cout << "." << boost::algorithm::trim_left_copy(s) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_right_copy(s) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_copy(s) << "." << std::endl;
}

Download source code

In order to automatically remove spaces on either end of a string, boost::algorithm::trim_left_copy(),


boost::algorithm::trim_right_copy() and boost::algorithm::trim_copy() can be used. Which character counts as a space is
dependent on the given global locale.

Boost.StringAlgorithms allows to provide a predicate as an additional parameter for different functions that determines to
which characters of the string the function is applied to. The predicated versions for trimming a string are named
boost::algorithm::trim_left_copy_if(), boost::algorithm::trim_right_copy_if() and boost::algorithm::trim_copy_if()
accordingly.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "--Boris Schling--";
std::cout << "." << boost::algorithm::trim_left_copy_if(s, boost::algorithm::is_any_of("-")) << "." <<
std::endl;
std::cout << "." <<boost::algorithm::trim_right_copy_if(s, boost::algorithm::is_any_of("-")) << "." <<
std::endl;
std::cout << "." <<boost::algorithm::trim_copy_if(s, boost::algorithm::is_any_of("-")) << "." <<
std::endl;
}

Download source code

The program in the above example accesses another function named boost::algorithm::is_any_of() which is a helper
function for creating a predicate verifying whether or not the character - passed as the parameter - exists in a given string.
Using boost::algorithm::is_any_of(), the character for trimming a string can be specified as has been done in the example
which uses the hyphen.

Boost.StringAlgorithms already provides numerous helper functions returning commonly used predicates.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "123456789Boris Schling123456789";
std::cout << "." << boost::algorithm::trim_left_copy_if(s, boost::algorithm::is_digit()) << "." <<
std::endl;
std::cout << "." <<boost::algorithm::trim_right_copy_if(s, boost::algorithm::is_digit()) << "." <<
std::endl;
std::cout << "." <<boost::algorithm::trim_copy_if(s, boost::algorithm::is_digit()) << "." <<
std::endl;
}

Download source code

The predicate returned by boost::algorithm::is_digit() indicates a numeric character by returning the boolean value true.
Helper functions are also provided to check whether or not a character is uppercase or lowercase:
boost::algorithm::is_upper() and boost::algorithm::is_lower() respectively. All of these functions use the global locale by
default unless otherwise specified by passing a different locale as a parameter.

Besides the predicates that verify individual characters of a string, Boost.StringAlgorithms also offers functions that work
with strings instead.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::starts_with(s, "Boris") << std::endl;
std::cout << boost::algorithm::ends_with(s, "Schling") << std::endl;
std::cout << boost::algorithm::contains(s, "is") << std::endl;
std::cout << boost::algorithm::lexicographical_compare(s, "Boris") << std::endl;
}

Download source code

The functions boost::algorithm::starts_with(), boost::algorithm::ends_with(), boost::algorithm::contains() and


boost::algorithm::lexicographical_compare() all compare two individual strings.

The following shows a function that allows to split a string into smaller parts.

#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
#include <vector>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::vector<std::string> v;
boost::algorithm::split(v, s, boost::algorithm::is_space());
std::cout << v.size() << std::endl;
}

Download source code

Using boost::algorithm::split(), a given string can be split into a container based on a certain delimiter. The function
requires a predicate as its third parameter indicating for each character whether the string should be split at the given
position. The example uses the helper function boost::algorithm::is_space() to create a predicate that will split the string at
every space character.

Many of the functions introduced in this paragraph also exist in a version that ignores the case of the string. They typically
have the same name except for a leading 'i'. For example, the equivalent to boost::algorithm::erase_all_copy() is
boost::algorithm::ierase_all_copy().

Finally, it should be noted that many functions of Boost.StringAlgorithms also support regular expressions. The following
program uses the boost::algorithm::find_regex() function to search for a regular expression.

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::iterator_range<std::string::iterator> r = boost::algorithm::find_regex(s,
boost::regex("\\w\\s\\w"));
std::cout << r << std::endl;
}

Download source code

In order to use the regular expression, the program accesses a class named boost::regex which is defined inside the Boost
C++ Library Boost.Regex and is presented in the following paragraph.

5.4 Boost.Regex

The Boost C++ Library Boost.Regex allows the usage of regular expressions in C++. Regular expressions is a powerful
feature of many languages that alleviates searching for a particular string pattern. While nowadays C++ still needs to
resort to a Boost C++ Library, support for regular expressions will become part of the C++ standard library in the future:
Boost.Regex is expected to be included in the next revision of the C++ standard.

The two most important classes in Boost.Regex are boost::regex and boost::smatch, both defined in boost/regex.hpp.
While the former is used to define a regular expression, the latter will save the search results.

Boost.Regex provides three different functions to search for regular expressions which are introduced below.

#include <boost/regex.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("\\w+\\s\\w+");
std::cout << boost::regex_match(s, expr) << std::endl;
}

Download source code

boost::regex_match() is used to compare a string with a regular expression. It will return true only if the expression
matches the complete string.

To search a string for a regular expression, boost::regex_search() is available.

#include <boost/regex.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("(\\w+)\\s(\\w+)");
boost::smatch what;
if (boost::regex_search(s, what, expr))
{
std::cout << what[0] << std::endl;
std::cout << what[1] << " " << what[2] << std::endl;
}
}

Download source code

boost::regex_search() expects a reference to an object of type boost::smatch as an additional parameter that is used to
store the results. boost::regex_search() only searches for groupings thus, the example actually returns two results based
on the two groupings found in the regular expression.

The result storage class boost::smatch is actually a container holding elements of type boost::sub_match which can be
accessed using an interface similar to the one of std::vector. For example, elements can be accessed via the operator[]()
operator.

The class boost::sub_match on the other hand saves iterators to the specific positions inside a string corresponding to the
grouping of a regular expression. Since it is derived from std::pair, the individual iterators referencing a particular substring
can be accessed using first and second. In order to write a substring to the standard output stream, these iterators do
not necessarily need to be accessed though as seen in the above example. Using the overloaded << operator, the
substring can be directly written instead.

Please note that since results are stored using iterators, boost::sub_match does not copy them. This certainly implies that
they are accessible only as long as the corresponding string - referenced by the iterators - exists.
Furthermore, please note that the first element of the container boost::smatch stores iterators referencing the string that
matches the complete regular expression. The first substring that matches the first grouping is accessible at index 1.

The third function offered by Boost.Regex is boost::regex_replace().


#include <boost/regex.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = " Boris Schling ";
boost::regex expr("\\s");
std::string fmt("_");
std::cout << boost::regex_replace(s, expr, fmt) << std::endl;
}

Download source code

Besides the string to search as well as the regular expression, boost::regex_replace() requires a format that defines how
substrings, matching individual groupings of the regular expression, are replaced. In case the regular expression does not
contain any grouping, corresponding substrings are replaced one-to-one using the given format. Thus, the above program
will output _Boris_Schling_ as the result.
boost::regex_replace() always searches through the complete string for the regular expression. Hence, the program
actually replaced all three spaces with underscores.

#include <boost/regex.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("(\\w+)\\s(\\w+)");
std::string fmt("\\2 \\1");
std::cout << boost::regex_replace(s, expr, fmt) << std::endl;
}

Download source code

The format can access substrings returned by groupings of the regular expression. The example uses this technique to
swap the first with the last name, displaying Schling Boris as the result.
Please note that there exist different standards for regular expressions and formats. Each of the three functions takes an
additional parameter that allows to select a specific standard. Whether or not special characters should be interpreted in a
specific format or whether the format should rather replace the complete string matching the regular expression can be
specified as well.

#include <boost/regex.hpp>
#include <locale>
#include <iostream>
int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("(\\w+)\\s(\\w+)");
std::string fmt("\\2 \\1");
std::cout << boost::regex_replace(s, expr, fmt, boost::regex_constants::format_literal) << std::endl;
}

Download source code

The program passes the boost::regex_constants::format_literal flag as the fourth parameter to boost::regex_replace() to
suppress handling of special characters in the format. Since the complete string that matches the regular expression is
replaced with the format, the output of the example is \2 \1 .
As indicated at the end of the previous paragraph, regular expressions can also be used with Boost.StringAlgorithms. The
library accesses Boost.Regex to provide functions such as boost::algorithm::find_regex(),
boost::algorithm::replace_regex(), boost::algorithm::erase_regex() and boost::algorithm::split_regex(). Since Boost.Regex
is expected to be part of the upcoming revision of the C++ standard, it is advisable to be proficient in applying regular
expressions without the usage of Boost.StringAlgorithms though.

5.5 Boost.Tokenizer

The library Boost.Tokenizer allows to iterate over partial expressions in a string by interpreting certain characters as
separators.

#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
tokenizer tok(s);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}

Download source code

Boost.Tokenizer defines a template class named boost::tokenizer in boost/tokenizer.hpp. It expects a class that identifies
coherent expressions for its template parameter. The above example uses the class boost::char_separator which interprets
spaces and punctuation marks as separators.

A tokenizer must be initialized with a string of type std::string. Using the begin() and end() methods, the tokenizer can be
accessed just like a container. Partial expressions of the string used to initialize the tokenizer are available via iterators.
How partial expressions are evaluated depends on the kind of class passed as the template parameter.
Since boost::char_separator interprets spaces and punctuation marks as separators by default, the example displays Boost ,
C , + , + and libraries . In order to identify these characters, boost::char_separator utilizes both std::isspace() and
std::ispunct(). Boost.Tokenizer distinguishes between separators that should be displayed and separators that should be
suppressed: By default, spaces are suppressed while punctuation marks are displayed. Hence the two plus signs are
displayed accordingly.

If punctuation marks should not be interpreted as separators, the boost::char_separator object can be initialized
accordingly before being passed to the tokenizer. The following example does exactly that.

#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
boost::char_separator<char> sep(" ");
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}

Download source code

The constructor of boost::char_separator expects a total of three parameters of which only the first one must be supplied.
It describes the individual separators that are suppressed. For the given example, spaces are treated as separators just
like with the previous example.

The second parameter specifies the separators that are displayed. In case this parameter is omitted, it is empty and thus
no separators are displayed at all. If the program is now executed, it displays Boost , C++ and libraries .
If a plus sign is passed for the second parameter, the example program behaves just like the first one.

#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
boost::char_separator<char> sep(" ", "+");
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}

Download source code

The third parameter determines whether or not empty partial expressions are displayed. If two separators are found back-
to-back, the corresponding partial expression is empty. By default, these empty expressions are not displayed. Using the
third parameter, the default behavior can be manipulated.

#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
boost::char_separator<char> sep(" ", "+", boost::keep_empty_tokens);
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}

Download source code

If executed, the above program displays two additional empty partial expressions. The first one is found between the two
plus signs while the second one is found between the second plus sign and the following space.

A tokenizer can also be used with different string types.

#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tokenizer<boost::char_separator<wchar_t>, std::wstring::const_iterator, std::wstring>
tokenizer;
std::wstring s = L"Boost C++ libraries";
boost::char_separator<wchar_t> sep(L" ");
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::wcout << *it << std::endl;
}

Download source code

This example iterates over a string of type std::wstring instead. In order to allow this type of string, the tokenizer must be
initialized using additional template parameters. The same applies to the boost::char_separator class; it also must be
initialized using wchar_t for its template parameter.

Besides boost::char_separator, Boost.Tokenizer provides two additional classes to identify partial expressions.

#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tokenizer<boost::escaped_list_separator<char> > tokenizer;
std::string s = "Boost,\"C++ libraries\"";
tokenizer tok(s);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}

Download source code


boost::escaped_list_separator is used to read multiple values separated by a comma. This format is commonly known as
CSV (comma separated values). It also considers double quotes as well as so-called escape sequences accordingly. The
output of the example is therefore Boost and C++ libraries .
The second class provided is boost::offset_separator which must be instantiated. The corresponding object must be passed
to the constructor of boost::tokenizer as the second parameter.

#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tokenizer<boost::offset_separator> tokenizer;
std::string s = "Boost C++ libraries";
int offsets[] = { 5, 5, 9 };
boost::offset_separator sep(offsets, offsets + 3);
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}

Download source code

boost::offset_separator specifies the locations within the string at which individual partial expressions end. The above
program specifies that the first partial expression ends after 5 characters, the second ends after additional 5 characters and
the third and last ends after the following 9 characters. The output will be Boost , C++ and libraries .

5.6 Boost.Format

Boost.Format offers a replacement for the std::printf() function defined in cstdio. std::printf() originates from the C
standard and allows formatted data output. However, it is neither type-safe nor expandable. In C++ applications,
Boost.Format is usually the preferred choice when data should be output in a formatted way.

The library Boost.Format provides a class named boost::format which is defined in boost/format.hpp. Similar to
std::printf(), a string containing special characters to control formatting is passed to the constructor of boost::format. The
actual data replacing these special characters in the output is linked via the % operator as shown in the following example.

#include <boost/format.hpp>
#include <iostream>
int main()
{
std::cout << boost::format("%1%.%2%.%3%") % 16 % 9 % 2008 << std::endl;
}

Download source code

Boost.Format uses numerics placed between two percent signs as placeholders that are later linked to the actual data using
the % operator. The above program uses the numbers 16, 9, and 2009 to form a date string in the format of 16.9.2008 . In
case the month should appear in front of the day, which is common in the United States, the placeholders can simply be
swapped to accommodate.

#include <boost/format.hpp>
#include <iostream>
int main()
{
std::cout << boost::format("%2%/%1%/%3%") % 16 % 9 % 2008 << std::endl;
}

Download source code

The program now displays 9/16/2008 instead.

To format data using the C++ manipulators, Boost.Format offers a function named boost::io::group().

#include <boost/format.hpp>
#include <iostream>
int main()
{
std::cout << boost::format("%1% %2% %1%") % boost::io::group(std::showpos, 99) % 100 << std::endl;
}

Download source code

The example will display +99 100 +99 as the result. Since the manipulator std::showpos() has been linked to the number 99
via boost::io::group(), the plus sign is automatically added whenever 99 is displayed.

If the plus sign should only be shown for the first output of 99, the format placeholder needs to be customized.

#include <boost/format.hpp>
#include <iostream>
int main()
{
std::cout << boost::format("%|1$+| %2% %1%") % 99 % 100 << std::endl;
}

Download source code

The placeholder %1% has been replaced with %|1$+|. Customization of a format not only adds two additional pipe signs
though. The reference to the data also is placed between the pipe signs and rather uses 1$ instead of 1%. This is required
in order to modify the output to +99 100 99 .
Please note that, even though references to data are optional in general, they must be specified either for all placeholders
or none. The following example only provides references for the second and third placeholder but omits them for the first
one which generates an error during execution.

#include <boost/format.hpp>
#include <iostream>
int main()
{
try
{
std::cout << boost::format("%|+| %2% %1%") % 99 % 100 << std::endl;
}
catch (boost::io::format_error &ex)
{
std::cout << ex.what() << std::endl;
}
}

Download source code

This program will throw an exception of type boost::io::format_error. Strictly speaking, Boost.Format throws
boost::io::bad_format_string. Since the different exception classes are all derived from boost::io::format_error, it is usually
easier catching exceptions of this type though.

The following examples shows how to write the program without having references to data.

#include <boost/format.hpp>
#include <iostream>
int main()
{
std::cout << boost::format("%|+| %|| %||") % 99 % 100 % 99 << std::endl;
}

Download source code

The pipe signs for the second and third placeholder can safely be omitted since they do not specify the format in this case.
The resulting syntax then closely resembles the one of std::printf().

#include <boost/format.hpp>
#include <iostream>
int main()
{
std::cout << boost::format("%+d %d %d") % 99 % 100 % 99 << std::endl;
}

Download source code

While the format may look like the one of std::printf(), Boost.Format still provides the advantage of type safety. The usage
of the letter 'd' within the format string does not indicate the output of a numeric but rather incorporates the std::dec()
manipulator on the internal stream object used by boost::format. This allows to specify format strings which would not
make sense for std::printf() and thus may result in a crash of the application during execution.

#include <boost/format.hpp>
#include <iostream>
int main()
{
std::cout << boost::format("%+s %s %s") % 99 % 100 % 99 << std::endl;
}

Download source code

While std::printf() uses the letter 's' only for strings of type const char*, the above program works perfectly. Boost.Format
does not expect a string necessarily but rather incorporates the appropriate manipulators to configure the operation mode
of the internal stream. Even in this case though, it is still possible to add the numbers to the internal stream as shown
above.

5.7 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Create a program that extracts and displays data such as first and last name, birthday and account balance from the
following XML stream: <person><name>Karl-Heinz Huber</name><dob>1970-9-
30</dob><account>2,900.64 USD</account></person>.

The first name should be displayed separated from the last name. The birthday should be shown using the typical
format of 'day.month.year' while the account balance should omit any decimal place. Test your application with
different XML streams that contain additional spaces, a second first name, a negative number for the account balance
and so forth.

2. Create a program that formats and displays data records such as the following: Munich Hamburg 92.12 8:25 9:45.
This record describes a flight from Munich to Hamburg that costs 92.12 Euro, departs at 8:25 AM and arrives at 9:45
AM. It should be displayed as: Munich-> Hamburg92.12 EUR (08:25-09:45) .
More detailed, the city should be 10-digit and left-aligned while the price should be 7-digit and right-aligned. After
the price, the currency should be displayed. The departure and arrival times should be shown in parenthesis, without
spaces and separated by a hyphen. For times prior to 10 AM/PM, a leading 0 should be added. Test your application
with different data records by e.g. adding a city that contains more than 10 digits.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter6:6:
Chapter Multithreading
Multithreading
Chapter 7: Asynchronous Input and Output

Chapter 6: Multithreading
Table of Contents 6.1 General
6.2 Thread Management
6.3 Synchronization
6.4 Thread Local Storage
6.5 Exercises

This book is licensed under a Creative Commons License.

6.1 General

Threads are discrete processing sequences that allow execution of different functions within a given application at the same
time. This becomes important if a function, known to take a long time for a specific calculation, should not block a different
function while executing. Threads actually allow the simultaneous execution of two functions without having one waiting for
the other.

Once an application is launched, it contains only one thread by default. This thread executes the main() function. Functions
called from within main() are executed sequentially in the context of this thread. Such a program is called a single
threaded application.

In contrast, programs that create new threads are called multithreaded applications. Not only can they execute multiple
functions at the same time, they also become more and more important these days since computers now ship with CPUs
containing more than one core by default. Since multiple cores allow the execution of different functions simultaneously,
they put a burden on the developer to use the available processing capacity accordingly. While threads have always been
used whenever different functions should execute concurrently, developers now are more and more forced to carefully
structure their applications to support this concurrency. Knowledge of multithreaded programming thus becomes more and
more important in the age of multi-core systems.

This chapter introduces the Boost C++ Library Boost.Thread that allows the development of platform independent
multithreaded applications.

6.2 Thread Management

The most important class in this library is boost::thread, defined in boost/thread.hpp, which is used to create a new
thread. The following example shows how to apply it.

#include <boost/thread.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << std::endl;
}
}
int main()
{
boost::thread t(thread);
t.join();
}

Download source code

The name of the function that should execute within the thread is passed to the constructor of boost::thread. Once the
variable t in the above example is created, the thread() function starts executing in its own thread immediately. At this
point, thread() executes concurrently with the main() function.

To keep the application from terminating, the join() method is called on the newly created thread. join() is a blocking call:
It blocks the current thread until the thread, for which join() was called, has terminated. This causes main() to wait until
thread() has terminated.

As seen in the above example, a particular thread can be accessed via a variable such as t in order to e.g. wait for its
termination using the join() method. However, the thread will continue to execute even if t loses its scope and is
destroyed. A thread always binds to a variable of type boost::thread in the beginning, but once created, depends no longer
on it. There even exists a method called detach() that allows to decouple a variable of type boost::thread from its
corresponding thread. Certainly, methods such as join() cannot be called afterwards since the variable does not represent a
valid thread any longer.

Anything that can be done inside a function can also be done inside a thread. Ultimately, a thread is no different than a
function - except that it is executed concurrently. In the example above, five numbers are written to the standard output
stream using a loop. To slow down the output, every iteration of the loop calls the wait() function to stall execution for one
second. wait() employs a function named sleep() that also originates from Boost.Thread and resides in the
boost::this_thread namespace.

sleep() either expects a period of time or a specific point in time indicating how long or until when the current thread
should be stalled. By passing an object of type boost::posix_time::seconds, a period of time is specified in this example.
boost::posix_time::seconds comes from the Boost.DateTime library that is used by Boost.Thread to manage and process
time data.
While the previous example shows how to wait for a different thread, the following example rather shows how a thread can
be interrupted by the means of so-called interruption points.

#include <boost/thread.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
void thread()
{
try
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << std::endl;
}
}
catch (boost::thread_interrupted&)
{
}
}
int main()
{
boost::thread t(thread);
wait(3);
t.interrupt();
t.join();
}

Download source code

Calling interrupt() on a thread object interrupts the corresponding thread. In this context, interrupted means that an
exception of type boost::thread_interrupted is thrown inside the thread. However, this only happens once the thread
reaches an interruption point.

Simply calling interrupt() does not cause anything if the given thread does not contain any interruption points. Whenever a
thread reaches an interruption point it will check whether the interrupt() method has been called. Only if it has, a
boost::thread_interrupted exception is thrown accordingly.

Boost.Thread defines a series of interruption points such as the sleep() function. Since sleep() is called five times in the
example, the thread checks five times whether or not it was interrupted. Between the calls to sleep(), the thread can not
be interrupted though.

Once the program is executed, it will only print three numbers to the standard output stream. This is caused by calling the
interrupt() method after three seconds inside main(). Thus, the corresponding thread is interrupted and throws a
boost::thread_interrupted exception accordingly. While the exception is correctly caught inside the thread, the catch
handler is empty though. Since the thread() function returns after the handler, the thread is terminated as well. This in
turn will also terminate the entire application since main() simply waited for the thread to terminate using the join()
method.

Boost.Thread defines about ten interruption points including the mentioned sleep() function. Thanks to these interruption
points, threads can easily be interrupted in a timely manner. However, they may not always be the best choice since an
interruption point must be reached first in order to check for the boost::thread_interrupted exception.

To provide a rough overview over the different functions provided by Boost.Thread, the following example introduces two
more.

#include <boost/thread.hpp>
#include <iostream>
int main()
{
std::cout << boost::this_thread::get_id() << std::endl;
std::cout << boost::thread::hardware_concurrency() << std::endl;
}

Download source code

Using the namespace boost::this_thread, independent functions are provided that apply to the current thread such as the
sleep() function shown before. Another one is get_id(): It will return a number identifying the current thread. It is also
provided as a method for boost::thread.

The static hardware_concurrency() method, provided by the boost::thread class, returns the number of threads that could
physically be executed at the same time based on the underlying number of CPUs or CPU cores. Calling this function on a
commonly used dual-core machine, a value of 2 is returned. This allows for a simple method to identify the theoretical
maximum number of threads that should be used simultaneously by a given multithreaded application.

6.3 Synchronization

While the usage of multiple threads can increase the performance of an application it usually also increases its complexity.
If several functions execute at the same time using threads, access to shared resources must be synchronized accordingly.
This involves quite some work once the application reaches a certain size. This paragraph introduces the classes provided
by Boost.Thread for synchronizing threads.

#include <boost/thread.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
boost::mutex mutex;
void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
mutex.lock();
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
mutex.unlock();
}
}
int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}

Download source code

Multithreaded programs use so-called mutex objects for synchronization. Boost.Thread provides different mutex classes,
boost::mutex being the most simple one. The basic principle of a mutex is to prevent other threads from taking ownership
while a particular thread owns it. Once released, a different thread can take ownership. This causes threads to wait until a
different thread has finished processing some operations and thus releases its ownership of the mutex object accordingly.

The above example uses a global mutex object of type boost::mutex named mutex. The thread() function takes ownership
of this object right before it writes to the standard output stream inside the for loop using the lock() method. Once a
message has been written, the ownership is released using the unlock() method.

main() creates two threads, both executing the thread() function. Using the for loop, every thread counts to five, writing a
message to the standard output stream with each iteration. Unfortunately, the standard output stream is a global object
which is shared among all threads. The standard does not provide any guarantee that std::cout can be safely accessed
from multiple threads. Thus, access to the standard output stream must be synchronized: At any given time, only one
thread is allowed to access std::cout.

Since both threads try to acquire the mutex before writing to the standard output stream, it is guaranteed that only one
thread at a time actually accesses std::cout. Disregarding which thread successfully calls the lock() method, all other
threads need to wait until unlock() has been called.

Acquiring and releasing mutexes is a typical scheme and is supported by Boost.Thread through different data types. For
example, instead of calling lock() and unlock() directly, the boost::lock_guard class can be used.

#include <boost/thread.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
boost::mutex mutex;
void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
}
}
int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}

Download source code

boost::lock_guard automatically calls lock() and unlock() inside its constructor and destructor, respectively. Access to the
shared resource is as synchronized as it was when calling both methods explicitly. The boost::lock_guard class is yet
another example of the RAII idiom presented in Chapter2, Smart Pointers.
Besides boost::mutex and boost::lock_guard, Boost.Thread provides additional classes to support variations of
synchronization. One of the essential ones is boost::unique_lock which, compared to boost::lock_guard, provides a number
of helpful methods.

#include <boost/thread.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
boost::timed_mutex mutex;
void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
boost::unique_lock<boost::timed_mutex> lock(mutex, boost::try_to_lock);
if (!lock.owns_lock())
lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(1));
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
boost::timed_mutex *m = lock.release();
m->unlock();
}
}
int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}
Download source code

The above example uses various methods to illustrate some of the features provided by boost::unique_lock. Certainly, the
usage of these features does not necessarily make sense for the given scenario; the usage of boost::lock_guard in the
previous example was already adequate. This example is rather meant to demonstrate the possibilities offered by
boost::unique_lock.

boost::unique_lock offers different ways of acquiring a mutex by providing multiple constructors. The one expecting only a
mutex object simply calls the lock() method and waits until the mutex has been acquired. It thus acts exactly the same as
the one of boost::lock_guard.

If a value of type boost::try_to_lock is passed as the second parameter, the corresponding constructor calls try_lock()
instead. This method returns a value of type bool: true if the mutex could be acquired, false if not. Opposed to the lock()
method, try_lock() returns immediately and does not block until the mutex has been acquired.

The above program passes boost::try_to_lock as the second parameter to the constructor of boost::unique_lock. Whether
or not the mutex has been acquired can be checked via the owns_lock() method afterwards. In case it has not -
owns_lock() returns false - another function provided by boost::unique_lock is used: timed_lock() waits for a certain time
to acquire the mutex. The given program waits for up to one second which should be more than enough time to acquire
the mutex.

The example actually shows the three fundamental ways of acquiring a mutex: lock() waits until the mutex has been
acquired. try_lock() does not wait but acquires the mutex if it is available at the time of the call and returns false
otherwise. Finally, timed_lock() tries to acquire the mutex within a given period of time. As with try_lock(), success or
failure is indicated by the return value of type bool.

While both lock() and try_lock() are provided by boost::mutex, timed_lock() is only supported by boost::timed_mutex
instead which is the reason for its usage in the above example program. Without using timed_lock(), the mutex can be of
type boost::mutex as seen in the previous example.

Just like boost::lock_guard, the destructor of boost::unique_lock releases the mutex accordingly. In addition, the mutex
can be manually released using the unlock() method. It is also possible to remove the association between the
boost::unique_lock class and the mutex by calling release() as done in the above example. In this case however, the
mutex must be released using the unlock() method explicitly as it is not done automatically by the destructor of
boost::unique_lock anymore.

boost::unique_lock is a so-called exclusive lock meaning that only one thread at a time can acquire the mutex. Other
threads are required to wait until the mutex has been released again. Besides exclusive locks there are also non-exclusive
ones. Boost.Thread provides a class named boost::shared_lock to support non-exclusive locks accordingly. This class must
be used together with a mutex of type boost::shared_mutex as shown in the following example.

#include <boost/thread.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
boost::shared_mutex mutex;
std::vector<int> random_numbers;
void fill()
{
std::srand(static_cast<unsigned int>(std::time(0)));
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::shared_mutex> lock(mutex);
random_numbers.push_back(std::rand());
lock.unlock();
wait(1);
}
}
void print()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
boost::shared_lock<boost::shared_mutex> lock(mutex);
std::cout << random_numbers.back() << std::endl;
}
}
int sum = 0;
void count()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
boost::shared_lock<boost::shared_mutex> lock(mutex);
sum += random_numbers.back();
}
}
int main()
{
boost::thread t1(fill);
boost::thread t2(print);
boost::thread t3(count);
t1.join();
t2.join();
t3.join();
std::cout << "Summe: " << sum << std::endl;
}

Download source code

Non-exclusive locks of type boost::shared_lock can be used if threads only need read-only access to a specific resource. A
thread modifying the resource needs write access and thus requires an exclusive lock. The reason for that should be
obvious: Threads with read-only access do not recognize other threads accessing the same resource at the same time.
Non-exclusive locks can therefore share a mutex.
In the given example, both print() and count() access random_numbers read-only. While the print() function writes the
last number of random_numbers to the standard output stream, the count() function adds it to the variable sum. Since
neither function modifies random_numbers, both can access it at the same time using a non-exclusive lock of type
boost::shared_lock.

Inside the fill() function, an exclusive lock of type boost::unique_lock is required since it inserts new random numbers into
random_numbers. The mutex is explicitly released using the unlock() method before fill() waits for one second. Opposed
to the previous example, wait() is called at the end of the for loop to guarantee that at least one random number exists in
the container before it is accessed by either print() or count(). Both of these functions call the wait() function at the
beginning of their for loop accordingly.

Looking at the individual calls to the wait() function from different locations, one potential issue becomes apparent: The
order of the function calls is directly affected by the order in which the CPU actually executes the individual threads. Using
so-called condition variables, the individual threads can be synchronized so that elements added to random_numbers are
immediately processed by a different thread accordingly.

#include <boost/thread.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
boost::mutex mutex;
boost::condition_variable_any cond;
std::vector<int> random_numbers;
void fill()
{
std::srand(static_cast<unsigned int>(std::time(0)));
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::mutex> lock(mutex);
random_numbers.push_back(std::rand());
cond.notify_all();
cond.wait(mutex);
}
}
void print()
{
std::size_t next_size = 1;
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::mutex> lock(mutex);
while (random_numbers.size() != next_size)
cond.wait(mutex);
std::cout << random_numbers.back() << std::endl;
++next_size;
cond.notify_all();
}
}
int main()
{
boost::thread t1(fill);
boost::thread t2(print);
t1.join();
t2.join();
}

Download source code

The program in this example removed the wait() and count() functions. Threads do no longer wait for one second with
every loop iteration but rather execute as fast as possible. Additionally, no total is calculated; numbers are solely written to
the standard output stream.

To ensure correct processing of the random numbers, the individual threads are synchronized by a conditional variable that
allows to check for certain conditions between multiple threads.

As before, the fill() function generates a random number with each iteration and places it in the random_numbers
container. To block other threads from accessing the container at the same time, an exclusive lock is taken accordingly.
Instead of waiting for one second, this example actually uses a conditional variable instead. Calling the notify_all() method
will wake up every thread that has been waiting for this notification by calling the wait() method, respectively.

By looking at the for loop of the print() function, one can see that for the same conditional variable a method named wait()
is called. If the thread is woken up by a call to notify_all(), it tries to acquire the mutex which will only succeed after it
has been successfully released in the fill() function.

The trick here is that calling wait() also releases the corresponding mutex passed as parameter. After calling notify_all(),
the fill() function releases the mutex by calling wait() accordingly. It then blocks and waits for some other thread to call
notify_all() which happens in the print() function once the random number has been written to the standard output stream.

Notice that the call to the wait() method inside the print() function actually happens within a separate while loop. This is
done to handle the scenario where a random number has already been placed in the container before the wait() method is
called for the first time in print(). By comparing the number of stored elements in random_numbers with the expected
number of elements, this scenario is successfully handled and the random number is written to the standard output
stream.

6.4 Thread Local Storage

Thread Local Storage (TLS) is a dedicated storage area that can only be accessed by one thread. TLS variables can be seen
as global variables only visible to a particular thread instead of the whole program. The following example shows the
benefits of these variables.

#include <boost/thread.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
void init_number_generator()
{
static bool done = false;
if (!done)
{
done = true;
std::srand(static_cast<unsigned int>(std::time(0)));
}
}
boost::mutex mutex;
void random_number_generator()
{
init_number_generator();
int i = std::rand();
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << i << std::endl;
}
int main()
{
boost::thread t[3];
for (int i = 0; i < 3; ++i)
t[i] = boost::thread(random_number_generator);
for (int i = 0; i < 3; ++i)
t[i].join();
}

Download source code

The example creates three threads, each writing a random number to the standard output stream. The
random_number_generator() function utilizes the std::rand() function, defined in the C++ standard, to create the random
numbers. However, the generator used for std::rand() must be properly initialized with the std::srand() function. If not,
the program will always print the same random number.

Initializing the random number generator takes place inside the init_number_generator() function with the aid of the
std::time() function returning the current time. Since this value differs every time the application is executed, it is
guaranteed that the generator is always initialized with a different value and thus provides new random numbers. Since
the generator only needs to be initialized once, init_number_generator() uses a static variable named done as the
condition.

If the program is executed a couple of times, it becomes apparent that two of the three random numbers written are
always the same. The program actually has a defect: The generator on which std::rand() is based must be initialized for
every thread using the function. Therefore, the implementation of init_number_generator() is actually incorrect since it only
calls std::srand() once. Using TLS, this defect can be rectified.

#include <boost/thread.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
void init_number_generator()
{
static boost::thread_specific_ptr<bool> tls;
if (!tls.get())
tls.reset(new bool(false));
if (!*tls)
{
*tls = true;
std::srand(static_cast<unsigned int>(std::time(0)));
}
}
boost::mutex mutex;
void random_number_generator()
{
init_number_generator();
int i = std::rand();
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << i << std::endl;
}
int main()
{
boost::thread t[3];
for (int i = 0; i < 3; ++i)
t[i] = boost::thread(random_number_generator);
for (int i = 0; i < 3; ++i)
t[i].join();
}

Download source code

The static variable done has been replaced with a TLS variable tls which is based on the template class
boost::thread_specific_ptr - instantiated with the data type bool. In principle, tls works just like done: It acts as a
condition indicating whether or not the random number generator has already been initialized. The crucial difference,
however, is that the value stored by tls is only visible and available to the corresponding thread.

Once a variable of type boost::thread_specific_ptr is created, it can be set accordingly. However, it now expects the
address of a variable of type bool instead of the variable itself. Using the reset() method, the corresponding address can be
stored in tls. In the given example, a variable of type bool is dynamically allocated and its address, returned by new, is
stored in tls. To avoid setting tls every time the init_number_generator() function is called, it first checks whether an
address is already stored via the get() method.

Since boost::thread_specific_ptr stores an address, it behaves like a regular pointer. Consequently, both the operator*()
and operator->() operators are overloaded to simplify the usage. The example uses *tls to check whether the condition is
currently true or false. Depending on the current condition, the random number generator is either initialized or not.

As seen, boost::thread_specific_ptr allows storing the address of an object for the current thread and only allows the
current thread to retrieve the same address later on. While one thread already stored the address successfully, a different
thread may have not.
If the program is now executed, it may come as a surprise that despite the TLS variable, the random numbers generated
are still equal. This is due to the fact that all three threads are created at the same time and thus, the random number
generators are initialized with the same time as well. If the program is executed a couple of times however, the random
numbers will change indicating that the generators itself are initialized correctly.
6.5 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Refactor the following program to calculate the total using two threads. Since many processors nowadays have two
cores, the execution time should decrease by utilizing threads.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/cstdint.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();
boost::uint64_t sum = 0;
for (int i = 0; i < 1000000000; ++i)
sum += i;
boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time();
std::cout << end - start << std::endl;
std::cout << sum << std::endl;
}

Download source code

2. Generalize the program from exercise 1 by utilizing as many threads as the processor can physically execute at the
same time. For example, if the processor contains four cores, a total of four threads should be utilized.

3. Change the following program by executing the thread() function in its own thread created in main(). The program
should calculate the total and write it to the standard output stream twice. The implementation of calculate(), print()
and thread() can be modified however, the signature of each function needs to stay the same. In other words, each
function should still neither require any parameters nor return a value.

#include <iostream>
int sum = 0;
void calculate()
{
for (int i = 0; i < 1000; ++i)
sum += i;
}
void print()
{
std::cout << sum << std::endl;
}
void thread()
{
calculate();
print();
}
int main()
{
thread();
}

Download source code


Copyright 2008-2010 Boris Schling
The Boost C++ Libraries Chapter7:7:
Chapter Asynchronous
Asynchronous Input
Input and Output
and Output
Chapter 8: Interprocess Communication

Chapter 7: Asynchronous Input and Output


Table of Contents 7.1 General
7.2 I/O Services and I/O Objects
7.3 Scalability and Multithreading
7.4 Network Programming
7.5 Developing Boost.Asio Extensions
7.6 Exercises

This book is licensed under a Creative Commons License.

7.1 General

This chapter introduces the Boost C++ Library Asio which centers on asynchronous input and output. The name says it all:
Asio stands for asynchronous input/output. This library allows C++ to process data asynchronously as well as platform
independent. Asynchronous data processing means that tasks are triggered without waiting for their completion. Instead,
Boost.Asio triggers an application once a task has completed. The main advantage of asynchronous tasks is the possibility
to perform other tasks without blocking the application while waiting for their completion.

Typical examples for asynchronous tasks are network applications. If data is sent over e.g. the Internet, it is generally
important to know whether or not it has been sent successfully. Without a library such as Boost.Asio, the return value of a
function would be evaluated. This, however, would require to wait until all data has been sent and either an acknowledge
or an error code is available. Using Boost.Asio, the process is split into two individual steps: The first step starts the data
transmission as an asynchronous task. Once the transmission has finished either successful or with an error, the application
is notified about the result in a second step accordingly. The crucial difference is that the application does not need to
block until the transmission has finished but can execute other operations in the meantime.

7.2 I/O Services and I/O Objects

Applications utilizing Boost.Asio for asynchronous data processing are based on so-called I/O services and I/O objects.
While I/O services abstract operating system interfaces that allow asynchronous data processing in the first place, I/O
objects are used to initiate certain operations. Whereas Boost.Asio only provides one class named boost::asio::io_service
for the I/O service, implemented as an optimized class for each operating system supported, it contains several classes for
the individual I/O objects. Among these, the class boost::asio::ip::tcp::socket is used to send and receive data over a
network while the class boost::asio::deadline_timer offers a timer that either elapses at a fixed point in time or after a
certain period. The timer is used in the following first example since it does not require any knowledge about network
programming compared to many of the remaining I/O objects provided by Asio.

#include <boost/asio.hpp>
#include <iostream>
void handler(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
int main()
{
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(5));
timer.async_wait(handler);
io_service.run();
}

Download source code

The function main() first defines an I/O service io_service that is used to initialize the I/O object timer. Just like
boost::asio::deadline_timer, all I/O objects typically expect an I/O service as their first argument to the constructor. Since
timer resembles an alarm, the constructor of boost::asio::deadline_timer can be passed a second argument indicating
either a point in time or a period after which the alarm should go off. The above example specifies a period of five seconds
for the alarm which starts counting once timer has been defined.

While it would be possible to call a function that returns after five seconds, an asynchronous operation is started with Asio
by calling the method async_wait() and passing the name of the handler() function as the single argument. Please note
that only the name of the handler() function is passed but the function itself is not called.
The advantage of async_wait() is that the function call returns immediately instead of waiting five seconds. Once the alarm
goes off, the function provided as the argument is called accordingly. The application thus can execute other operations
after calling async_wait() instead of just blocking.

A method such as async_wait() is described as non-blocking. I/O objects typically also provide blocking methods in case
the execution flow should be blocked until a certain operation has finished. For example, the blocking wait() method could
have been called for boost::asio::deadline_timer instead. Since it is a blocking call, it does not require a function name but
rather returns at a specific point in time or after a certain period.

While looking at the source code of the above example, it can be noticed that after the call to async_wait(), a method
named run() is called on the I/O service. This is mandatory since control needs to be taken over by the operating system
in order to call the handler() function after five seconds.

While async_wait() starts an asynchronous operation and returns immediately, run() actually blocks. Execution therefore
stops at the call of run(). Ironically, many operating systems support asynchronous operations via a blocking function only.
The following example shows why this limitations is typically not an issue.

#include <boost/asio.hpp>
#include <iostream>
void handler1(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
void handler2(const boost::system::error_code &ec)
{
std::cout << "10 s." << std::endl;
}
int main()
{
boost::asio::io_service io_service;
boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(10));
timer2.async_wait(handler2);
io_service.run();
}

Download source code

The above application now utilizes two I/O objects of type boost::asio::deadline_timer. The first I/O object represents an
alarm going off after five seconds while the second one represents an alarm going off after ten seconds. After each period
has elapsed, the functions handler1() and handler2() are called accordingly.

The run() method is again called on the sole I/O service at the end of main(). As previously mentioned, this function
actually blocks execution passing control to the operating system which takes over the asynchronous processing. With the
aid of the operating system, the handler1() function is called after five seconds while the handler2() function is called after
10 seconds, respectively.

At first sight, it may come as a surprise that asynchronous processing requires calling the blocking run() method. However,
since the application needs to be prevented from terminating, this does actually not pose any issue. If run() would not
block, main() would actually finish and thus terminate the application. If execution of the application should not be blocked,
run() should be called within a new thread since it naturally blocks the current thread only.

Once all asynchronous operations of the particular I/O service have been completed, controls is returned back to the run()
method which simply returns. Both example applications terminate once all the alarms have gone off.

7.3 Scalability and Multithreading

Developing an application using a library such as Boost.Asio differs from the usual C++ style. Functions that may take
longer to return are no longer called in a sequential manner. Instead of calling blocking functions, Boost.Asio starts
asynchronous operations instead. Functions that are required to be called once the operation has finished are implemented
within the corresponding handler. The drawback of this approach is the physical separation of the sequentially executed
functions which certainly makes the corresponding code more difficult to understand.

A library such as Boost.Asio is typically used to achieve a higher efficiency of the application. Without the need to wait for
a particular function to finish, an application can perform other tasks in between, e.g. starting another operation that may
take a while to complete.

Scalability describes the property of an application to effectively benefit from additional resources. Using Boost.Asio is
already recommended if long-lasting operations should not block other operations. Since today's PCs are typically equipped
with multi-core processors, the usage of threads can increase the scalability of an application based on Boost.Asio even
further.

If the run() method is called on an object of type boost::asio::io_service, the associated handlers are invoked within the
same thread. By using multiple threads, an application can call multiple run() methods simultaneously. Once an
asynchronous operation has finished, the corresponding I/O service will then execute the handler within one of the threads.
If a second operation has finished shortly after the first, the I/O service can execute the handler within a different thread
without needing to wait for the first handler to terminate.

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
void handler1(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
void handler2(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
boost::asio::io_service io_service;
void run()
{
io_service.run();
}
int main()
{
boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(5));
timer2.async_wait(handler2);
boost::thread thread1(run);
boost::thread thread2(run);
thread1.join();
thread2.join();
}

Download source code

The example from the previous section is now converted to a multithreaded application. Using the boost::thread class,
defined in boost/thread.hpp and part of the Boost C++ Library Thread, two threads are created within main(). Both
threads are calling the run() method for the single I/O service. This allows the I/O service to utilize both threads for
executing handler functions once individual asynchronous operations have completed.

Both timers in the example application are set to elapse after five seconds. Since two threads are available, both
handler1() and handler2() can be executed simultaneously. If the second timer elapses while the handler of the first one is
still executed, the second handler is executed within the second thread. If the handler of the first timer has already
terminated, the I/O service is free to choose either thread.

Threads can increase the performance of an application. Since threads are executed on processor cores, there is no sense
in creating more threads than there are cores. This ensures that each thread is executed on its own core without battling
with other threads for the corresponding core.

Please note that the usage of threads does not always make sense. Running the above example can result in a mixed
output of the individual messages on the standard output stream since the two handlers, which may run in parallel, access
a single shared resource: The standard output stream std::cout. The access needs to be synchronized in order to
guarantee that each message is written completely before a different thread can write another message to the standard
output stream. The usage of threads in this scenario does not provide much benefit as long as the individual handlers
cannot be independently executed in parallel.

Calling the run() method of a single I/O service multiple times is the recommended way of adding scalability to any
application based on Boost.Asio. Alternatively, there is a different method: Instead of binding multiple threads to a single
I/O service, multiple I/O services can be created instead. Each of the I/O services then utilizes one thread. If the number
of I/O services matches the number of processor cores on the system, asynchronous operations can be executed on their
own core.

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
void handler1(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
void handler2(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
boost::asio::io_service io_service1;
boost::asio::io_service io_service2;
void run1()
{
io_service1.run();
}
void run2()
{
io_service2.run();
}
int main()
{
boost::asio::deadline_timer timer1(io_service1, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service2, boost::posix_time::seconds(5));
timer2.async_wait(handler2);
boost::thread thread1(run1);
boost::thread thread2(run2);
thread1.join();
thread2.join();
}

Download source code

The already known example application using two timers has now been rewritten to utilize two I/O services. The application
is still based on two threads; however, each thread is now bound to an individual I/O service. Additionally, the two I/O
objects timer1 and timer2 are now also bound to the different I/O services.

The functionality of the application is the same as before. It can be beneficial under certain conditions to have multiple I/O
services, each with its own thread and ideally running on its own processor core, since asynchronous operations including
their handlers then can execute locally. If no distant data or function needs to be accessed, each I/O service acts as a
small autonomous application. Local and distant in this case refers to resources such as cache and memory pages. Since
specific knowledge about the underlying hardware, operation system, compiler as well as potential bottlenecks is required
before optimization strategies can be developed, multiple I/O services should only be used in scenarios that clearly benefit
from them.

7.4 Network Programming

Even though Boost.Asio is a library that can process any kind of data asynchronously, it is mainly being used for network
programming. This is due to the fact that Boost.Asio supported network functions long before additional I/O objects were
added over time. Network functions are a perfect example for asynchronous processing since the transmission of data
within a network may take longer and thus acknowledges as well as error conditions are not directly available.

Boost.Asio provides many I/O objects to develop network applications. The following example uses the
boost::asio::ip::tcp::socket class to establish a connection to a different PC and download the 'Highscore' homepage; just
like a browser does when pointed to www.highscore.de.

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <string>
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::socket sock(io_service);
boost::array<char, 4096> buffer;
void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{
if (!ec)
{
std::cout << std::string(buffer.data(), bytes_transferred) << std::endl;
sock.async_read_some(boost::asio::buffer(buffer), read_handler);
}
}
void connect_handler(const boost::system::error_code &ec)
{
if (!ec)
{
boost::asio::write(sock, boost::asio::buffer("GET / HTTP 1.1\r\nHost: highscore.de\r\n\r\n"));
sock.async_read_some(boost::asio::buffer(buffer), read_handler);
}
}
void resolve_handler(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator it)
{
if (!ec)
{
sock.async_connect(*it, connect_handler);
}
}
int main()
{
boost::asio::ip::tcp::resolver::query query("www.highscore.de", "80");
resolver.async_resolve(query, resolve_handler);
io_service.run();
}

Download source code

The most obvious part of the application is the usage of three handlers: The connect_handler() and read_handler()
functions are called once the connection has been established and while data are being received, respectively. Why is the
resolve_handler() function required though?

The Internet uses so-called IP addresses to identify individual PCs. IP addresses are essentially just a lengthy number that
is hard to remember. It is much easier to remember names such as www.highscore.de instead. In order to use such a
name for the Internet, it needs to be translated into the corresponding IP address via a process called name resolution.
The process is accomplished by a so-called name resolver which explains the name of the corresponding I/O object:
boost::asio::ip::tcp::resolver.
Name resolution is a process that requires a connection to the Internet as well. Dedicated PCs, called DNS servers, act just
like a phone book and know what IP address is assigned to an individual PC. Since the process itself is transparent, it is
only important to understand the concept behind it and why the boost::asio::ip::tcp::resolver I/O object is therefore
required. Since name resolution does not take place locally, it is also implemented as an asynchronous operation. The
resolve_handler() function is called once the name resolution has either succeeded or terminated with an error.

Since receiving data presumes a successful connection which in turn presumes a successful name resolution, different
asynchronous operations are started within the individual handlers. resolve_handler() accesses the I/O object sock to
create a connection using the resolved address provided by the iterator it. sock is also being accessed inside of
connect_handler() to send the HTTP request and to initiate the data reception. Since all of these operations are
asynchronous, the names of the individual handlers are being passed as arguments. Depending on the corresponding
handler, additional arguments are required such as the iterator it pointing to the resolved address or the buffer buffer
storing the received data.

Once executed, the application creates an object query of type boost::asio::ip::tcp::resolver::query that represents a
query containing the name www.highscore.de and the, in the Internet commonly used, port 80. This query is passed to the
async_resolve() method to resolve the name. Finally, main() simply calls the run() method of the I/O service to transfer
control over the asynchronous operations to the operating system.

Once the name resolution process has finished, resolve_handler() is called which checks whether or not the name could be
resolved. If successfully resolved, the object ec, containing the various error conditions, is set to 0. Only in this case, the
socket is accessed to create a connection accordingly. The server address is provided via the second argument of type
boost::asio::ip::tcp::resolver::iterator.

After calling the async_connect() method, connect_handler() is called automatically. Inside the handler, the ec object is
evaluated to check whether or not a connection has been established. In case a connection is available, the
async_read_some() method is called for the corresponding socket which initiates the read operation. To store the received
data, a buffer is provided as the first argument. In the given example, it is of type boost::array which is part of the Boost
C++ Library Array and is defined in boost/array.hpp.

The read_handler() function is called every time one or more bytes have been received and stored within the buffer. The
exact number of bytes received is given via the argument bytes_transferred which is of type std::size_t. As is the rule,
the handler should first evaluate the argument ec to check for any reception error. If successfully received, the data is
simply written to the standard output stream.

Please note that read_handler() calls the async_read_some() method again once the data has been written via std::cout.
This is necessary since there is no guarantee that the whole homepage has been received with just one single
asynchronous operation. The alternating calls of async_read_some() and read_handler() only stop if the connection has
been disrupted, e.g. when the web server has transmitted the complete homepage. In this case, an error is reported inside
read_handler() which prevents further data output on the standard output stream as well as further invocations of the
async_read() method for this particular socket. The example application will actually terminate since no further
asynchronous operations are outstanding.

While the previous example was used to retrieve the homepage of www.highscore.de, the next example actually illustrates
a simple web server. The crucial difference is that the application does not connect to other PCs but rather waits for
incoming connections.

#include <boost/asio.hpp>
#include <string>
boost::asio::io_service io_service;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 80);
boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint);
boost::asio::ip::tcp::socket sock(io_service);
std::string data = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";
void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{
}
void accept_handler(const boost::system::error_code &ec)
{
if (!ec)
{
boost::asio::async_write(sock, boost::asio::buffer(data), write_handler);
}
}
int main()
{
acceptor.listen();
acceptor.async_accept(sock, accept_handler);
io_service.run();
}

Download source code

The I/O object acceptor of type boost::asio::ip::tcp::acceptor - initialized with the protocol and the port - is used to wait
for incoming connections from other PCs. The initialization happens via the endpoint object which is of type
boost::asio::ip::tcp::endpoint and configures the acceptor in the example to use port 80 to wait for incoming connections
of version 4 of the Internet protocol which is typically the port and protocol used for the WWW.

After initializing the acceptor, main() first calls the listen() method to put the acceptor into receive mode before it waits for
the initial connection using the async_accept() method. The socket used to send and receive data is passed as the first
argument.

Once a PC tries to establish a connection, accept_handler() is called automatically. If the connection request was
successful, the free-standing boost::asio::async_write() function is invoked to send the information stored in data via the
socket. boost::asio::ip::tcp::socket also provides a method named async_write_some() to send data; however, it will
invoke the associated handler whenever at least one byte has been sent. The handler would need to calculate how many
bytes are left to send and invoke async_write_some() repeatedly until all bytes have been sent. This can be avoided by
using boost::asio::async_write() since this asynchronous operation only terminates after all bytes of the buffer have been
sent.

Once all data has been sent, the empty function write_handler() is called in this example. Since all asynchronous operations
have finished, the application is terminated. The connection to the other PC is closed accordingly.

7.5 Developing Boost.Asio Extensions

Even though Boost.Asio mainly supports network functions, adding additional I/O objects to perform different asynchronous
operations is fairly easy. This section outlines the general layout of a Boost.Asio extension. While it is not mandatory, it
provides a viable skeleton as a starting point for other extensions.

To add new asynchronous operations to Boost.Asio, three classes need to be implemented:

A class derived from boost::asio::basic_io_object representing the new I/O object. Developers using the new
Boost.Asio extension will exclusively encounter this I/O object.

A class derived from boost::asio::io_service::service representing a service that is registered with the I/O service and
can be accessed from the I/O object. The differentiation between the service and the I/O object is important since
there is only one instance of the service per I/O service at any given time but a service can be accessed by multiple
I/O objects.

A class not derived from any other class representing the service implementation. Since there is only one instance of
a service per I/O service at any given time, the service creates an instance of its implementation for every I/O
object. This instance manages the internal data pertinent to the corresponding I/O object.

Instead of just providing the skeleton, the Boost.Asio extension developed in this section is going to resemble the available
boost::asio::deadline_timer object. The difference between the two is that the period for the timer is being passed as an
argument to the wait() or async_wait() method instead of the constructor.

#include <boost/asio.hpp>
#include <cstddef>
template <typename Service>
class basic_timer
: public boost::asio::basic_io_object<Service>
{
public:
explicit basic_timer(boost::asio::io_service &io_service)
: boost::asio::basic_io_object<Service>(io_service)
{
}
void wait(std::size_t seconds)
{
return this->service.wait(this->implementation, seconds);
}
template <typename Handler>
void async_wait(std::size_t seconds, Handler handler)
{
this->service.async_wait(this->implementation, seconds, handler);
}
};

Download source code

Every I/O object is usually implemented as a template class that is required to be instantiated with a service - typically
with the service specifically developed for this I/O object. Whenever an I/O object is instantiated, the service is
automatically registered with the I/O service by the parent class boost::asio::basic_io_object, unless it was already
registered previously. This ensures that services used by any I/O object will only be registered once per I/O service.

The corresponding service is accessible within the I/O object via the service reference and is typically accessed to forward
method calls to the service. Since services need to store data for every I/O object, an instance is automatically created for
every I/O object using the service. This again happens with the aid of the parent class boost::asio::basic_io_object. The
actual service implementation is passed as an argument to any method call to allow the service to specifically know which
I/O object initiated the call. The service implementation is accessible via the implementation property.

In general, any I/O object is relatively simple: While the installation of the service as well as the creation of a service
implementation is done by the parent class boost::asio::basic_io_object, method calls are simply forwarded to the
corresponding service; passing the actual service implementation of the I/O object as an argument.

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/system/error_code.hpp>
template <typename TimerImplementation = timer_impl>
class basic_timer_service
: public boost::asio::io_service::service
{
public:
static boost::asio::io_service::id id;
explicit basic_timer_service(boost::asio::io_service &io_service)
: boost::asio::io_service::service(io_service),
async_work_(new boost::asio::io_service::work(async_io_service_)),
async_thread_(boost::bind(&boost::asio::io_service::run, &async_io_service_))
{
}
~basic_timer_service()
{
async_work_.reset();
async_io_service_.stop();
async_thread_.join();
}
typedef boost::shared_ptr<TimerImplementation> implementation_type;
void construct(implementation_type &impl)
{
impl.reset(new TimerImplementation());
}
void destroy(implementation_type &impl)
{
impl->destroy();
impl.reset();
}
void wait(implementation_type &impl, std::size_t seconds)
{
boost::system::error_code ec;
impl->wait(seconds, ec);
boost::asio::detail::throw_error(ec);
}
template <typename Handler>
class wait_operation
{
public:
wait_operation(implementation_type &impl, boost::asio::io_service &io_service, std::size_t
seconds, Handler handler)
: impl_(impl),
io_service_(io_service),
work_(io_service),
seconds_(seconds),
handler_(handler)
{
}
void operator()() const
{
implementation_type impl = impl_.lock();
if (impl)
{
boost::system::error_code ec;
impl->wait(seconds_, ec);
this->io_service_.post(boost::asio::detail::bind_handler(handler_, ec));
}
else
{
this->io_service_.post(boost::asio::detail::bind_handler(handler_,
boost::asio::error::operation_aborted));
}
}
private:
boost::weak_ptr<TimerImplementation> impl_;
boost::asio::io_service &io_service_;
boost::asio::io_service::work work_;
std::size_t seconds_;
Handler handler_;
};
template <typename Handler>
void async_wait(implementation_type &impl, std::size_t seconds, Handler handler)
{
this->async_io_service_.post(wait_operation<Handler>(impl, this->get_io_service(), seconds,
handler));
}
private:
void shutdown_service()
{
}
boost::asio::io_service async_io_service_;
boost::scoped_ptr<boost::asio::io_service::work> async_work_;
boost::thread async_thread_;
};
template <typename TimerImplementation>
boost::asio::io_service::id basic_timer_service<TimerImplementation>::id;

Download source code

In order to be integrated with Boost.Asio, a service must fulfill a couple of requirements:

It needs to be derived from boost::asio::io_service::service. The constructor must expect a reference to an I/O
service which is passed to the constructor of boost::asio::io_service::service accordingly.

Any service must contain a static public property id of type boost::asio::io_service::id. Services are identified using
this property within the I/O service.

Two public methods named construct() and destruct(), both expecting an argument of type implementation_type,
must be defined. implementation_type is typically a type definition for the service implementation. As shown in the
above example, a boost::shared_ptr object can be used to easily instantiate a service implementation in construct()
and to destruct it in destruct() accordingly. Since both methods are automatically being called whenever an I/O
object is created or destroyed, a service can create and destroy service implementations for each I/O object using
construct() and destruct(), respectively.

A method named shutdown_service() must be defined; however, it can be private. For common Boost.Asio
extensions, this is usually an empty method. It is only being used by services that are more tightly integrated with
Boost.Asio. Nonetheless, the method must be present in order to compile the extension successfully.

In order to forward method calls to the corresponding service, methods for forwarding need to be defined for the I/O
object accordingly. These methods are typically named similar to the methods of the I/O object itself, e.g. wait() and
async_wait() in the above example. While synchronous methods such as wait() solely access the service implementation to
call a blocking method, the trick for asynchronous operations like async_wait() is to call the blocking method within a
thread.

Using the asynchronous operations with the help of a thread is usually done by accessing a new I/O service. The above
example contains a property named async_io_service_ of type boost::asio::io_service. The run() method of this I/O
service is started within its own thread created with async_thread_ of type boost::thread inside the constructor of the
service. The third property async_work_ of type boost::scoped_ptr<boost::asio::io_service::work> is required to avoid
the run() method from returning immediately. This could otherwise happen since there are no outstanding asynchronous
operations at creation. Creating an object of type boost::asio::io_service::work and binding it to the I/O service, which
also happens inside the service constructor, prevents the run() method from returning immediately.

A service could also be implemented without accessing its own I/O service - a single thread would be sufficient. The reason
for using a new I/O service for any additional thread is quite simple: Threads can communicate fairly easy with each other
using the I/O service. In the example, async_wait() creates a function object of type wait_operation and passes it to the
internal I/O service via the post() method. The overloaded operator()() of this function object is then called inside the
thread used to execute the run() method for the internal I/O service. post() offers a simple way of executing a function
object within a different thread.

The overloaded operator()() operator of wait_operation essentially performs the same work as the wait() method: Calling
the blocking wait() method of the service implementation. There is, however, the possibility that the I/O object, including
its service implementation, is destroyed while the thread executes the operator()() operator. If the service implementation
is destroyed in destruct(), the operator()() operator should no longer access it. This is prevented by using a weak pointer
known from the first chapter: The weak pointer impl_ returns a shared pointer to the service implementation if it still
exists when lock() is called, otherwise it will return 0. In that case, operator()() does not access the service implementation
but rather calls the handler with an error of boost::asio::error::operation_aborted.

#include <boost/system/error_code.hpp>
#include <cstddef>
#include <windows.h>
class timer_impl
{
public:
timer_impl()
: handle_(CreateEvent(NULL, FALSE, FALSE, NULL))
{
}
~timer_impl()
{
CloseHandle(handle_);
}
void destroy()
{
SetEvent(handle_);
}
void wait(std::size_t seconds, boost::system::error_code &ec)
{
DWORD res = WaitForSingleObject(handle_, seconds * 1000);
if (res == WAIT_OBJECT_0)
ec = boost::asio::error::operation_aborted;
else
ec = boost::system::error_code();
}
private:
HANDLE handle_;
};

Download source code

The service implementation timer_impl uses Windows API functions and can only be compiled and used in Windows. Its
purpose is rather to illustrate a potential implementation.

timer_impl exhibits two essential methods: wait() is called to wait for one or more seconds. destroy() is used to cancel a
wait operation which is mandatory since the wait() method is called inside its own thread for asynchronous operations. If
the I/O object, including its service implementation, is destroyed, the blocking wait() method should be canceled as soon as
possible which is done using destroy().

This Boost.Asio extension can be used as follows.

#include <boost/asio.hpp>
#include <iostream>
#include "basic_timer.hpp"
#include "timer_impl.hpp"
#include "basic_timer_service.hpp"
void wait_handler(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
typedef basic_timer<basic_timer_service<> > timer;
int main()
{
boost::asio::io_service io_service;
timer t(io_service);
t.async_wait(5, wait_handler);
io_service.run();
}
Download source code

Compared to the example application in the beginning of this chapter, this Boost.Asio extension is used similarly to
boost::asio::deadline_timer. In practice, boost::asio::deadline_timer should be preferred since it is already integrated with
Boost.Asio. The sole purpose of this extension was to show how Boost.Asio can be extended with new asynchronous
operations.
Directory Monitor is a real-world example of a Boost.Asio extension that provides an I/O object able to monitor directories.
If a file inside a monitored directory is created, modified or deleted, a handler is called accordingly. The current version
supports both Windows and Linux (Kernel version 2.6.13 or higher).

7.6 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Modify the server from Section7.4, Network Programming to prevent it from terminating after a single request but
rather processes an arbitrary number.

2. Extend the client from Section7.4, Network Programming to immediately parse the received HTML code for a URL.
If found, the corresponding resource should be downloaded as well. For this exercise, the first URL found should be
utilized. Ideally, the website as well as the resource should be saved in two files rather than writing both to the
standard output stream.

3. Create a client/server application to transmit a file between two PCs. Once the server is started, it should display the
IP addresses of all local interfaces and wait for client connections. One of the available server IP addresses as well as
the name of a local file should be passed to the client as command-line arguments. The client should transmit the
file to the server which in turn saves it accordingly. While transmitting, the client should provide some visual
indication of the progress to the user.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter8:8:
Chapter Interprocess
Interprocess Communication
Communication
Chapter 9: Filesystem

Chapter 8: Interprocess Communication


Table of Contents 8.1 General
8.2 Shared Memory
8.3 Managed Shared Memory
8.4 Synchronization
8.5 Exercises

This book is licensed under a Creative Commons License.

8.1 General

Interprocess communication describes mechanisms to exchange data between different applications running on the same
computer. This does not include network communication though. If data is required to be exchanged between applications
running on different computers connected via network, take a look at Chapter7, Asynchronous Input and Output which
covers the Boost.Asio library.

This chapter presents the Boost.Interprocess library that contains numerous classes providing an abstract layer for
operating system specific interprocess communication interfaces. Even though the concepts of interprocess communication
are closely related between different operating systems, the interfaces can vary greatly. Boost.Interprocess allows a
platform independent access to these functions from C++.

While Boost.Asio can be used for exchanging data between applications running on the same computer as well, the
performance using Boost.Interprocess is usually better. Boost.Interprocess actually accesses operating system functions
optimized for the data exchange between applications running on the same computer and thus should be the first choice
whenever data exchange without a network is required.

8.2 Shared Memory

Shared memory is typically the fastest form of interprocess communication. It provides a memory area that is shared
between different applications. One application can write data to the area while another application can read the same data
accordingly.

Such a memory area is represented in Boost.Interprocess by the boost::interprocess::shared_memory_object class. To use


this class, the boost/interprocess/shared_memory_object.hpp header file needs to be included.
#include <boost/interprocess/shared_memory_object.hpp>
#include <iostream>
int main()
{
boost::interprocess::shared_memory_object shdmem(boost::interprocess::open_or_create, "Highscore",
boost::interprocess::read_write);
shdmem.truncate(1024);
std::cout << shdmem.get_name() << std::endl;
boost::interprocess::offset_t size;
if (shdmem.get_size(size))
std::cout << size << std::endl;
}

Download source code

The constructor of boost::interprocess::shared_memory_object expects three parameters. The first one specifies whether
the shared memory should be created or just opened. The above example actually does it either way: using
boost::interprocess::open_or_create, the shared memory is opened if it already exists, otherwise it will be created.

Opening an existing shared memory assumes that it has been created before. To uniquely identify a shared memory, a
name is being assigned accordingly. The second parameter passed to the constructor of
boost::interprocess::shared_memory_object specifies that name.

The third and last parameter determines how an application can access the shared memory. The shown application can
both read from and write to the shared memory due to the boost::interprocess::read_write value.

After creating an object of type boost::interprocess::shared_memory_object, a corresponding shared memory exists within
the operating system. The size of this memory area, however, is initially 0. In order to utilize the area, the truncate()
method needs to be called, passing the requested size of the shared memory in bytes. For the above example, the shared
memory provides space for 1,024 bytes.

Please note that the truncate() method can only be called if the shared memory has been opened with
boost::interprocess::read_write. If not, an exception of type boost::interprocess::interprocess_exception will be thrown.

In order to adjust the size of the shared memory, the truncate() method can be called repeatedly.

After creating a shared memory, methods such as get_name() and get_size() can be used to query the name and the size,
respectively.

Since shared memory is used to exchange data between different applications, each application needs to map the shared
memory into its address space which is done via the boost::interprocess::mapped_region class.

It may come as a surprise that two classes are actually used in order to access the shared memory. However, the
boost::interprocess::mapped_region class can also be used to map different objects into the address space of a particular
application. For example, Boost.Interprocess provides a boost::interprocess::file_mapping class which essentially represents
a shared memory for a particular file. Thus, an object of type boost::interprocess::file_mapping corresponds to a file. Data
written to such an object is automatically saved in the associated physical file. Since boost::interprocess::file_mapping
does not load the file completely but rather maps arbitrary parts into the address space using
boost::interprocess::mapped_region, it is possible to process files of several gigabytes in size that can not be completely
loaded into memory on 32-bit systems otherwise.
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>
int main()
{
boost::interprocess::shared_memory_object shdmem(boost::interprocess::open_or_create, "Highscore",
boost::interprocess::read_write);
shdmem.truncate(1024);
boost::interprocess::mapped_region region(shdmem, boost::interprocess::read_write);
std::cout << std::hex << "0x" << region.get_address() << std::endl;
std::cout << std::dec << region.get_size() << std::endl;
boost::interprocess::mapped_region region2(shdmem, boost::interprocess::read_only);
std::cout << std::hex << "0x" << region2.get_address() << std::endl;
std::cout << std::dec << region2.get_size() << std::endl;
}

Download source code

In order to use the boost::interprocess::mapped_region class, the header boost/interprocess/mapped_region.hpp needs to


be included. An object of type boost::interprocess::shared_memory_object must be passed as the first argument to the
constructor of boost::interprocess::mapped_region. The second argument determines whether the memory area can be
accessed read-only or whether applications are allowed to write to it as well.

The above example creates two objects of type boost::interprocess::mapped_region: The shared memory named Highscore
is mapped twice into the address space of the process. The address as well as the size of the mapped memory area is
written to the standard output stream using the get_address() and get_size() methods. While get_size() returns 1024 in
both cases, the return value of get_address() is different.

The following example uses the mapped memory area to write and read a number.

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>
int main()
{
boost::interprocess::shared_memory_object shdmem(boost::interprocess::open_or_create, "Highscore",
boost::interprocess::read_write);
shdmem.truncate(1024);
boost::interprocess::mapped_region region(shdmem, boost::interprocess::read_write);
int *i1 = static_cast<int*>(region.get_address());
*i1 = 99;
boost::interprocess::mapped_region region2(shdmem, boost::interprocess::read_only);
int *i2 = static_cast<int*>(region2.get_address());
std::cout << *i2 << std::endl;
}

Download source code

By means of region, the number 99 is written to the beginning of the shared memory. region2 then accesses the same
location of the shared memory to write the number to the standard output stream. Even though region and region2
represent different memory areas within the process as seen by the return value of get_address() in the previous example,
the program prints 99 since both memory areas access the same underlying shared memory.

Usually, multiple objects of type boost::interprocess::mapped_region would not be used for the shared memory within the
same application. There is actually not much sense accessing the same shared memory using two different memory areas.
The above example is only meant for illustration purposes.

In order to delete a particular shared memory, boost::interprocess::shared_memory_object offers the static remove()
method which takes the name of the shared memory to be deleted as its argument.

Boost.Interprocess kind of supports the RAII concept known from the chapter about smart pointers using a separate class
named boost::interprocess::remove_shared_memory_on_destroy. Its constructor expects the name of an existing shared
memory. If an object of this class is destroyed, the contained shared memory is automatically deleted within the
destructor.

Please note that the constructor of boost::interprocess::remove_shared_memory_on_destroy does not create or open the
shared memory. Therefore, this class is not a typical representative of the RAII concept.

#include <boost/interprocess/shared_memory_object.hpp>
#include <iostream>
int main()
{
bool removed = boost::interprocess::shared_memory_object::remove("Highscore");
std::cout << removed << std::endl;
}

Download source code

If remove() is not being called at all, the shared memory continues to exist even if the application is terminated. Whether
or not the shared memory is deleted depends on the underlying operating system. While many Unix operating systems,
including Linux, automatically delete a shared memory once the system is restarted, remove() must be called while
working with Windows or Mac OS X. Both systems actually store the shared memory as a persistent file which is still
available after a restart.

Windows provides a special kind of shared memory that is automatically deleted once the last application using it has been
terminated. In order to use it, the boost::interprocess::windows_shared_memory class, defined in
boost/interprocess/windows_shared_memory.hpp, is provided.

#include <boost/interprocess/windows_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>
int main()
{
boost::interprocess::windows_shared_memory shdmem(boost::interprocess::open_or_create, "Highscore",
boost::interprocess::read_write, 1024);
boost::interprocess::mapped_region region(shdmem, boost::interprocess::read_write);
int *i1 = static_cast<int*>(region.get_address());
*i1 = 99;
boost::interprocess::mapped_region region2(shdmem, boost::interprocess::read_only);
int *i2 = static_cast<int*>(region2.get_address());
std::cout << *i2 << std::endl;
}

Download source code

Please note that boost::interprocess::windows_shared_memory does not provide a truncate() method. Instead, the size of
the shared memory needs to be passed as the fourth argument to the constructor.

Even though the boost::interprocess::windows_shared_memory class is not portable and can only be used within Windows,
it is helpful while exchanging data between different applications that use this special kind of shared memory.

8.3 Managed Shared Memory

The previous section introduced the class boost::interprocess::shared_memory_object used to create and manage a shared
memory. In practice, this class is hardly used though since it requires to read and write individual bytes from and to the
shared memory. Conceptually, C++ rather promotes creating objects of classes and hiding the specifics of where and how
they are stored in memory.

Boost.Interprocess provides a concept named managed shared memory through the


boost::interprocess::managed_shared_memory class defined in boost/interprocess/managed_shared_memory.hpp. With the
aid of this class, objects can be instantiated in a way that the memory required by the individual object is located in
shared memory making each object automatically available to other applications accessing the same shared memory.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>
int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create,
"Highscore", 1024);
int *i = managed_shm.construct<int>("Integer")(99);
std::cout << *i << std::endl;
std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer");
if (p.first)
std::cout << *p.first << std::endl;
}

Download source code

The above example opens the shared memory named Highscore with a size of 1,024 bytes. In case it does not exist, it will
be automatically created.

While in a regular shared memory individual bytes are being directly accessed in order to read or write data, managed
shared memory uses methods such as construct(). This method expects a data type as its template argument - in the
example type int is declared. The method itself expects a name to denote the object created in the managed shared
memory. The example uses the name 'Integer'.

Since construct() returns a proxy object, arguments can be passed to it in order to initialize the created object. The syntax
looks like a call to a constructor. This ensures that objects not only can be created in a managed shared memory but also
can be initialized as desired.

To access a particular object in the managed shared memory, the find() method is used. By passing the name of the
object to find, find() returns either a pointer to the particular object or 0 in case no object with the given name was
found.

As seen in the above example, find() actually returns an object of type std::pair. The pointer to the object is provided as
the first property. What is provided as the second property though?

#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>
int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create,
"Highscore", 1024);
int *i = managed_shm.construct<int>("Integer")[10](99);
std::cout << *i << std::endl;
std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer");
if (p.first)
{
std::cout << *p.first << std::endl;
std::cout << p.second << std::endl;
}
}

Download source code

This time, an array for ten elements of type int is created by providing the value 10 enclosed by square brackets after the
call to construct(). The same 10 is written to the standard output stream using the second property. Using this property,
objects returned by the find() method can be distinguished between single objects and array objects. For the former,
second is set to 1 while for the latter it will specify the number of elements in the array.

Please note that all ten elements within the array are initialized with the value 99. It is not possible to initialize individual
elements with different values.

construct() will fail if there exists an object with the given name in the managed shared memory already. In this case,
construct() returns 0. If the existing object should be reused in case it already exists, the find_or_construct() method can
be used which returns a pointer to the existing object if found. In this case, no initialization happens.

There are other cases that cause construct() to fail as shown in the following example.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>
int main()
{
try
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create,
"Highscore", 1024);
int *i = managed_shm.construct<int>("Integer")[4096](99);
}
catch (boost::interprocess::bad_alloc &ex)
{
std::cerr << ex.what() << std::endl;
}
}

Download source code

The application tries to create an array of type int containing 4,096 elements. The managed shared memory, however, only
contains 1,024 bytes. Therefore, the requested memory cannot be provided by the shared memory causing an exception of
type boost::interprocess::bad_alloc to be thrown.

Once objects have been created in a managed shared memory, they can be deleted using the destroy() method.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>
int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create,
"Highscore", 1024);
int *i = managed_shm.find_or_construct<int>("Integer")(99);
std::cout << *i << std::endl;
managed_shm.destroy<int>("Integer");
std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer");
std::cout << p.first << std::endl;
}

Download source code

As its single argument, the name of the object to be deleted is passed to destroy(). If required, the return value of type
bool can be checked to verify whether the given object has been found and deleted successfully. Since an object will
always be deleted if found, the return value of false indicates that no object with the given name was found.

Besides destroy(), another method named destroy_ptr() is provided which can be used to pass a pointer to an object in the
managed shared memory. It also can be used to delete arrays.

Since managed shared memory makes it fairly easy to store objects shared between different applications, it seems natural
to use the containers from the C++ Standard Template Library as well. These containers allocate required memory
independently using new though. In order to use these containers in managed shared memory, they need to be advised to
rather allocate the memory in the shared memory.

Unfortunately, many implementations of the C++ Standard Template Library are not flexible enough to use the provided
containers such as std::string or std::list together with Boost.Interprocess. One example for such an implementation is the
one that ships with Microsoft Visual Studio 2008.

In order to allow developers the possibility to use the containers known from the C++ standard, Boost.Interprocess offers
more flexible implementations of them in the namespace boost::interprocess. For example, boost::interprocess::string acts
exactly as its C++ counterpart std::string with the advantage that its objects can be safely stored in a managed shared
memory.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <iostream>
int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create,
"Highscore", 1024);
typedef boost::interprocess::allocator<char,
boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> string;
string *s = managed_shm.find_or_construct<string>("String")("Hello!",
managed_shm.get_segment_manager());
s->insert(5, ", world");
std::cout << *s << std::endl;
}

Download source code

To create a string that will allocate required memory within the same managed shared memory it resides, a corresponding
data type must be defined in order to use a different allocator, provided by Boost.Interprocess, rather than the default
allocator provided by the C++ standard.

For this purpose, Boost.Interprocess offers the class boost::interprocess::allocator defined in


boost/interprocess/allocators/allocator.hpp. Using this class, an allocator can be created that internally uses the so-called
segment manager of the managed shared memory. The segment manager is responsible for the management of the
memory within a managed shared memory. Using the newly created allocator, a corresponding data type for the string can
be defined. As indicated above, it uses boost::interprocess::basic_string rather than std::basic_string. The new data type -
in the example simply named string - is based on boost::interprocess::basic_string and accesses the segment manager via
its allocator. In order to let the particular instance of string, created by a call to find_or_construct(), know which segment
manager it should access, a pointer to the corresponding segment manager is passed as the second argument to the
constructor.

Alongside boost::interprocess::string, Boost.Interprocess provides implementations for many other containers known from
the C++ standard. For example, boost::interprocess::vector and boost::interprocess::map defined in
boost/interprocess/containers/vector.hpp and boost/interprocess/containers/map.hpp, respectively.

Whenever the same managed shared memory is accessed from different applications, operations such as creating, finding
and destroying objects are automatically synchronized. If two applications try to create objects with different names in the
managed shared memory, the access is serialized accordingly. In order to execute multiple operations at once without
being interrupted by operations from a different application, the atomic_func() method can be used.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/bind.hpp>
#include <iostream>
void construct_objects(boost::interprocess::managed_shared_memory &managed_shm)
{
managed_shm.construct<int>("Integer")(99);
managed_shm.construct<float>("Float")(3.14);
}
int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create,
"Highscore", 1024);
managed_shm.atomic_func(boost::bind(construct_objects, boost::ref(managed_shm)));
std::cout << *managed_shm.find<int>("Integer").first << std::endl;
std::cout << *managed_shm.find<float>("Float").first << std::endl;
}

Download source code

atomic_func() expects a function, taking no arguments and not returning any value, as its single argument. The passed
function will be called in a fashion that ensures exclusive access to the managed shared memory - but only for operations
such as creating, finding or deleting objects. If another application has a pointer to an object within the managed shared
memory, it can access and modify this object using its pointer.

Boost.Interprocess can also be used to synchronize object access. Since Boost.Interprocess does not know who can access
the individual objects at what point in time, the synchronization needs to be explicitly stated. The classes provided for
synchronization are introduced in the following section.

8.4 Synchronization

Boost.Interprocess allows multiple applications to use a shared memory concurrently. Since shared memory is by definition
"shared" between these applications, Boost.Interprocess needs to support some form of synchronization.

While thinking about synchronization, the library Boost.Thread certainly comes to mind. As can be seen in Chapter6,
Multithreading, Boost.Thread indeed provides different concepts such as mutex objects and conditional variables to
synchronize threads. Unfortunately, these classes can only be used to synchronize threads within the same application;
they do not support the synchronization of different applications. Since the challenge in both cases is the same, the
concepts are no different.

While synchronization objects such as mutex objects and conditional variables reside within the same address space in
multithreaded applications and therefore are available to all threads, the challenge with shared memory is that independent
applications need to share these objects appropriately. For example, if one application creates a mutex object, it needs to
be accessible from a different application somehow.

Boost.Interprocess offers two kinds of synchronization objects: Anonymous objects are directly stored in the shared
memory which makes them automatically available to all applications. Named objects are managed by the operating
system and thus are not stored in the shared memory. They can be referenced by applications via their name.

The following example creates and uses a named mutex object by using the boost::interprocess::named_mutex class
defined in boost/interprocess/sync/named_mutex.hpp.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <iostream>
int main()
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm",
1024);
int *i = managed_shm.find_or_construct<int>("Integer")();
boost::interprocess::named_mutex named_mtx(boost::interprocess::open_or_create, "mtx");
named_mtx.lock();
++(*i);
std::cout << *i << std::endl;
named_mtx.unlock();
}

Download source code

Besides a parameter specifying whether the mutex object should be created or opened, the constructor of
boost::interprocess::named_mutex expects a name for it. Every application that knows that name is able to open the same
mutex object. In order to get access to the data in the shared memory, the application needs to take ownership of the
mutex object by calling the lock() method. Since mutex objects can only be owned by one application at any time, another
application may need to wait until the mutex object has been released using the unlock() method by the first application.
Once an application obtained ownership of a mutex object, it has exclusive access to the resource it guards. In the above
example the resource is a variable of type int that is incremented and written to the standard output stream.

If the application is started multiple times, every instance will print a value incremented by 1 compared to the previous
value. Thanks to the mutex object, the access to the shared memory and the variable itself is synchronized between the
different applications.

The following application uses an anonymous mutex object of type boost::interprocess::interprocess_mutex defined in
boost/interprocess/sync/interprocess_mutex.hpp. In order to be accessible for all applications, it is stored in the shared
memory.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <iostream>
int main()
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm",
1024);
int *i = managed_shm.find_or_construct<int>("Integer")();
boost::interprocess::interprocess_mutex *mtx =
managed_shm.find_or_construct<boost::interprocess::interprocess_mutex>("mtx")();
mtx->lock();
++(*i);
std::cout << *i << std::endl;
mtx->unlock();
}

Download source code

The application behaves exactly like the previous one. The only difference is the mutex object which is now stored directly
in the shared memory using the construct() or find_or_construct() method of the
boost::interprocess::managed_shared_memory class.

Besides the lock() method, both boost::interprocess::named_mutex and boost::interprocess::interprocess_mutex provide


the try_lock() and timed_lock() methods. They behave exactly like their counterparts provided by the mutex classes of
Boost.Thread.

In case recursive mutex objects are required, Boost.Interprocess offers the two classes
boost::interprocess::named_recursive_mutex and boost::interprocess::interprocess_recursive_mutex.

While mutex objects guarantee exclusive access to a shared resource, conditional variables control who has to have
exclusive access at what time. In general, the conditional variables provided by Boost.Interprocess work the same way as
the ones provided by Boost.Thread. They also have very similar interfaces which makes users of Boost.Thread feel
immediately at home when using these variables in Boost.Interprocess.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
int main()
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm",
1024);
int *i = managed_shm.find_or_construct<int>("Integer")(0);
boost::interprocess::named_mutex named_mtx(boost::interprocess::open_or_create, "mtx");
boost::interprocess::named_condition named_cnd(boost::interprocess::open_or_create, "cnd");
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(named_mtx);
while (*i < 10)
{
if (*i % 2 == 0)
{
++(*i);
named_cnd.notify_all();
named_cnd.wait(lock);
}
else
{
std::cout << *i << std::endl;
++(*i);
named_cnd.notify_all();
named_cnd.wait(lock);
}
}
named_cnd.notify_all();
boost::interprocess::shared_memory_object::remove("shm");
boost::interprocess::named_mutex::remove("mtx");
boost::interprocess::named_condition::remove("cnd");
}

Download source code

The example uses a conditional variable of type boost::interprocess::named_condition defined in


boost/interprocess/sync/named_condition.hpp. Since it is a named variable, it does not need to be stored in shared
memory.

The application uses a while loop to increment a variable of type int that is stored in shared memory. While the variable is
incremented with each iteration of the loop, it will only be written to the standard output stream with every second
iteration: Only odd numbers are written.

Every time, the variable has been incremented by 1, the wait() method of the conditional variable named_cnd is called. A
so-called lock - in the example the variable lock - is passed to this method. The lock has the same meaning as it does in
Boost.Thread: It is based on the RAII concept by taking ownership of a mutex object inside the constructor and releasing it
inside the destructor.

The lock is created before the while loop and thus takes ownership of the mutex object for the complete execution of the
application. However, if passed to the wait() method as an argument, it is automatically released.
Conditional variables are used to wait for a signal indicating that the wait is now over. The synchronization is controlled by
the wait() and notify_all() methods. If an application calls the wait() method, the ownership of the corresponding mutex
object is released before it waits until the notify_all() method is called for the same conditional variable.

If started, the application does not seem to do much: While the variable is incremented from 0 to 1 within the while loop,
the application then waits for a signal using the wait() method. In order to provide the signal, the application needs to be
started a second time.

The second instance of the application is going to try to take ownership of the same mutex object before entering the
while loop. This succeeds since the first instance of the application released ownership of the mutex object by calling
wait(). Since the variable has been incremented once, the second instance will now execute the else branch of the if
expression which will write the current value to the standard output stream before incrementing it by 1.

Now the second instance also calls the wait() method. However, before it does, it calls the notify_all() method which is
important in order to have the two instances cooperate correctly. The first instance is notified and tries to take ownership
of the mutex object again, which is still owned by the second instance though. Since the second instance calls the wait()
method right after notify_all(), which automatically releases the ownership, the first instance can take the ownership at
that point.

Both instances alternate, incrementing the variable in the shared memory. Only one instance writes the value to the
standard output stream though. As soon as the variable reaches the value 10, the while loop is finished. In order to have
the other instance not waiting for a signal forever, notify_all() is called one more time after the loop. Before terminating,
the shared memory, the mutex object as well as the conditional variable is destroyed.

Just like there are two types of mutex objects - an anonymous type that must be stored in shared memory as well as a
named type - there also exists two type of conditional variables. The previous example is now rewritten using an
anonymous conditional variable instead.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
int main()
{
try
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm",
1024);
int *i = managed_shm.find_or_construct<int>("Integer")(0);
boost::interprocess::interprocess_mutex *mtx =
managed_shm.find_or_construct<boost::interprocess::interprocess_mutex>("mtx")();
boost::interprocess::interprocess_condition *cnd =
managed_shm.find_or_construct<boost::interprocess::interprocess_condition>("cnd")();
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(*mtx);
while (*i < 10)
{
if (*i % 2 == 0)
{
++(*i);
cnd->notify_all();
cnd->wait(lock);
}
else
{
std::cout << *i << std::endl;
++(*i);
cnd->notify_all();
cnd->wait(lock);
}
}
cnd->notify_all();
}
catch (...)
{
}
boost::interprocess::shared_memory_object::remove("shm");
}

Download source code

The application works exactly like the previous one and thus needs to be started twice as well in order to increment the
variable ten times. The differences between the two examples are minimal. Whether anonymous or named conditional
variables are used is essentially irrelevant.

Besides mutex objects and conditional variables, Boost.Interprocess also supports so-called semaphores and file locks.
Semaphores behave similar to conditional variables with the exception that they do not distinguish between two states but
rather are based upon a counter. File locks on the other hand behave like mutex objects although they are not about
objects in memory but rather about files in the file system.

Just like Boost.Thread distinguishes between different types of mutex objects and locks, Boost.Interprocess also provides
several mutex objects and locks. For example, mutex objects that not only can be owned exclusive but also non-exclusive.
This is helpful if multiple applications need to read data simultaneously but write the data exclusively. Different classes for
locks are available to apply the RAII concept to the individual mutex objects.

Please note that names should be unique unless anonymous synchronization objects are used. Even though mutex objects
and conditional variables are objects based on different classes, this may not necessarily hold true for the operating system
dependent interfaces prescinded by Boost.Interprocess. In Windows, the same operating system functions are used for both
mutex objects and conditional variables. If the same name is used for both these objects, the application will not behave
correctly in Windows.

8.5 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Create a client/server application that communicates via shared memory. The name of a file should be passed as a
command line parameter to the client application. This file should be sent to the server application via shared
memory where it is saved locally in the same directory from which the server application was started.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter9:9:
Chapter Filesystem
Filesystem
Chapter 10: Date and Time

Chapter 9: Filesystem
Table of Contents 9.1 General
9.2 Paths
9.3 Files and Directories
9.4 File Streams
9.5 Exercises

This book is licensed under a Creative Commons License.

9.1 General

The library Boost.Filesystem simplifies working with files and directories. It provides a class named boost::filesystem::path
that allows to process paths. In addition, many functions are available to create directories or to validate a given file for
example.

9.2 Paths

boost::filesystem::path is the central class in Boost.Filesystem representing path information and providing methods to
process them.

In particular, boost::filesystem::path is actually a typedef for boost::filesystem::basic_path<std::string>. Additionally,


boost::filesystem::wpath is provided as a typedef for boost::filesystem::basic_path<std::wstring>.

All definitions are part of the boost::filesystem namespace which is defined in boost/filesystem.hpp.

Paths can be built by passing a corresponding string to the boost::filesystem::path class.

#include <boost/filesystem.hpp>
int main()
{
boost::filesystem::path p1("C:\\");
boost::filesystem::path p2("C:\\Windows");
boost::filesystem::path p3("C:\\Program Files");
}
Download source code

None of the constructors of boost::filesystem::path actually validates the path provided or checks whether or not the given
file or directory exists. Thus, boost::filesystem::path can be instantiated even with meaningless paths.

#include <boost/filesystem.hpp>
int main()
{
boost::filesystem::path p1("...");
boost::filesystem::path p2("\\");
boost::filesystem::path p3("@:");
}

Download source code

The reason the above program can be executed without any issue is that paths are just strings. boost::filesystem::path
only processes strings; the file system is not being accessed.

boost::filesystem::path certainly provides methods to retrieve a path as a string. Interestingly, there are three different
methods available.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\Windows\\System");
std::cout << p.string() << std::endl;
std::cout << p.file_string() << std::endl;
std::cout << p.directory_string() << std::endl;
}

Download source code

The string() method returns a so-called portable path. In other words, Boost.Filesystem uses its own predefined rules to
normalize the given string. In the above example, string() returns C:/Windows/System . As can be seen, Boost.Filesystem
internally uses the slash character / as the separator for file and directory names.

The whole purpose of portable paths is to uniquely identify files and directories across different platforms such as Windows
or Linux. The usage of preprocessor macros to encode paths depending on the underlying operating system is therefore no
longer needed. The rules for building portable paths mostly comply with the POSIX standard and are outlined in the
Boost.Filesystem reference.

Please note that the constructor of boost::filesystem::path supports both portable and platform dependent paths. The path
"C:\\Windows\\System" used in the above example is not portable but rather specific to Windows. It will be recognized
correctly by Boost.Filesystem but only if the program is executed on the Windows operating system! When executed on a
POSIX compliant operating system such as Linux, string() will actually return C:\Windows\System . Since the backslash
character \ in Linux is not used as a separator in neither the portable nor the native format, Boost.Filesystem does not
recognize it as being a separator for files and directories either.
Many times, it will be inevitable to use platform dependent paths as strings. One example is the usage of operating system
functions that expect a platform dependent encoding. The file_string() and directory_string() methods are offered for
exactly this purpose.

Both methods return C:\Windows\System in the above example - independent of the underlying operating system. While the
string is a valid path on Windows, it is neither portable nor platform dependent on a Linux system as explained in the
previous section.

The following example uses a portable path to initialize boost::filesystem::path.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("/");
std::cout << p.string() << std::endl;
std::cout << p.file_string() << std::endl;
std::cout << p.directory_string() << std::endl;
}

Download source code

Since string() returns a portable path, it equals the one used to initialize boost::filesystem::path: / . The file_string() and
directory_string() methods, however, return different results based on the underlying platform. In Windows, both return \
while in Linux, both return / instead.

One might wonder why there are two different methods returning platform dependent paths. Until now, file_string() and
directory_string() always returned the same value in the shown examples. However, there are operating systems that may
return different results. Since Boost.Filesystem aims to support as many operating systems as possible, it actually provides
two methods to accommodate accordingly. Even though one may be more familiar with Windows or POSIX systems such as
Linux, it is recommended to use file_string() for retrieving path information for files and directory_string() for retrieving
path information for directories, respectively. This certainly increases the portability of the code.

boost::filesystem::path provides several methods to access certain components of a path.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\Windows\\System");
std::cout << p.root_name() << std::endl;
std::cout << p.root_directory() << std::endl;
std::cout << p.root_path() << std::endl;
std::cout << p.relative_path() << std::endl;
std::cout << p.parent_path() << std::endl;
std::cout << p.filename() << std::endl;
}

Download source code


If executed on a Windows operating system, the string "C:\\Windows\\System" is interpreted as a platform dependent path
information. Consequently, root_name() returns C: , root_directory() returns / , root_path() returns C:/ , relative_path()
returns Windows/System , parent_path() returns C:/Windows , and filename() returns System .
As seen, no platform dependent path information is returned. None of the returned values contains a backslash \ but rather
a slash /. If platform dependent information is required, file_string() or directory_string() should be used instead. In order
to use these methods on individual components of a path, a new object of type boost::filesystem::path must be created
and initialized accordingly.

If the above program is executed on a Linux operating system instead, the returned values are different. Most of the
methods return an empty character stream except relative_path() and filename() which return C:\Windows\System instead.
Thus, the string "C:\\Windows\\System" is interpreted as a file name in Linux which is understandable given that it is
neither a portable encoding of a path nor a platform depending encoding supported by Linux. Boost.Filesystem therefore
has no other choice than interpreting the complete string as a file name.

Boost.Filesystem also provides additional methods to verify whether a specific substring is contained within a path. These
methods are: has_root_name(), has_root_directory(), has_root_path(), has_relative_path(), has_parent_path() and
has_filename(). Each method returns a value of type bool.

There are two more methods used to split a file name into its components. These should only be applied if has_filename()
returned true though. Otherwise, they will simply return empty strings since if there is no file name, there is nothing to
split.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("photo.jpg");
std::cout << p.stem() << std::endl;
std::cout << p.extension() << std::endl;
}

Download source code

The program returns photo for stem() as well as .jpg for extension(), respectively.

Instead of accessing the components of a path via method calls, one can also iterate over the components itself.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\Windows\\System");
for (boost::filesystem::path::iterator it = p.begin(); it != p.end(); ++it)
std::cout << *it << std::endl;
}

Download source code


If executed on Windows, the program will successively output C: , / , Windows and System . On a different operating system
such as Linux, the output will rather be C:\Windows\System .
While the previous examples showed various methods to access different components of a path, the following example
shows a method to modify path information instead.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\");
p /= "Windows\\System";
std::cout << p.string() << std::endl;
}

Download source code

Using the overloaded operator/=() operator, the example appends a path to another one. In Windows, the program will
output C:\Windows\System accordingly. In Linux, the output will rather be C:\/Windows\System since the slash character / is the
separator for files and directories. The slash is also the reason for overloading the operator/=() operator: After all, the
slash is part of the method name.

Besides the operator/=(), Boost.Filesystem offers only the remove_filename() and replace_extension() methods for
modifying path information.

9.3 Files and Directories

The methods presented with boost::filesystem::path internally simply process strings. They allow to access individual
components of a path, appending paths to each other and so on.

In order to work with physical files and directories on the hard drive, several independent functions are provided. They
expect one or more parameters of type boost::filesystem::path and call operating system functions for the passed files or
directories internally.

Prior to introducing different functions, it is important to understand what happens in the case of an error. All of the
functions access operating system functions internally that certainly can fail. In case of a failure, an exception of type
boost::filesystem::filesystem_error will be thrown. This class is derived from boost::system::system_error and thus fits
itself within the Boost.System framework.

Apart from the what() and code() methods, inherited from the parent class boost::system::system_error, two additional
methods are available: path1() and path2(). Both return an object of type boost::filesystem::path so that path information
can be determined easily in case of an error - even while working with functions expecting two parameters of type
boost::filesystem::path.

Many functions exist in two variations: One throwing an exception of type boost::filesystem::filesystem_error while the
other returns an object of type boost::system::error_code in case of a failure. For the latter one, the return value needs to
be explicitly inspected to determine a failure.
The following example introduces a function that allows to query the status of a file or directory.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\");
try
{
boost::filesystem::file_status s = boost::filesystem::status(p);
std::cout << boost::filesystem::is_directory(s) << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

boost::filesystem::status() returns an object of type boost::filesystem::file_status that can be passed to additional helper
functions for evaluation. For example, boost::filesystem::is_directory() will return true if the status for a directory was
queried. Besides boost::filesystem::is_directory(), other functions such as boost::filesystem::is_regular_file(),
boost::filesystem::is_symlink() and boost::filesystem::exists() are available, all returning a value of type bool.

Apart from boost::filesystem::status(), a second function named boost::filesystem::symlink_status() exists that can be
used to query the status of a symbolic link. In this case, the status of the file referred to by the symbolic link is actually
queried. In Windows, symbolic links are recognized by the lnk file extension.

A different category of functions allows to query the attributes instead.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\Windows\\win.ini");
try
{
std::cout << boost::filesystem::file_size(p) << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

The boost::filesystem::file_size() function returns the size of a file in bytes.

#include <boost/filesystem.hpp>
#include <iostream>
#include <ctime>
int main()
{
boost::filesystem::path p("C:\\Windows\\win.ini");
try
{
std::time_t t = boost::filesystem::last_write_time(p);
std::cout << std::ctime(&t) << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

To determine the time a file was modified last, boost::filesystem::last_write_time() is used.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\");
try
{
boost::filesystem::space_info s = boost::filesystem::space(p);
std::cout << s.capacity << std::endl;
std::cout << s.free << std::endl;
std::cout << s.available << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

boost::filesystem::space() is used to retrieve the total and remaining disk space. It returns an object of type
boost::filesystem::space_info that defines three public properties: capacity, free and available. All properties are of type
boost::uintmax_t which is defined in the Boost.Integer library and is typically a typedef for unsigned long long. The disk
space is therefore calculated in bytes.

While all functions presented so far leave files and directories untouched, there exist several functions that allow to create,
rename or delete files and directories.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("C:\\Test");
try
{
if (boost::filesystem::create_directory(p))
{
boost::filesystem::rename(p, "C:\\Test2");
boost::filesystem::remove("C:\\Test2");
}
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

The above example should be self-explanatory. By looking closely, it can be seen that not always an object of type
boost::filesystem::path is passed to the individual function but rather a simple string. This is actually possible since
boost::filesystem::path offers a non-explicit constructor which will convert simple strings to objects of type
boost::filesystem::path internally. This actually simplifies the usage of Boost.Filesystem since the creation of explicit objects
is not required.

Additional functions such as create_symlink() to create a symbolic link or copy_file() to copy a file or directory are available
as well.

The following example presents a function that creates an absolute path based on a file name or section of a path.

#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
try
{
std::cout << boost::filesystem::complete("photo.jpg") << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

Which path is actually displayed depends on the directory the program is executed within. If for example executed from
within C:\, the output will be C:/photo.jpg .
Please note again the slash character /! If a platform dependent path is desired, an object of type boost::filesystem::path
needs to be initialized and file_string() must be called.

To retrieve an absolute path relative to a different directory, a second parameter can be passed to
boost::filesystem::complete().
#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
try
{
std::cout << boost::filesystem::complete("photo.jpg", "D:\\") << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

Now the program displays D:/photo.jpg .

Finally, a useful helper function to retrieve the current working directory is shown in the following example.

#include <windows.h>
#include <boost/filesystem.hpp>
#include <iostream>
int main()
{
try
{
std::cout << boost::filesystem::current_path() << std::endl;
SetCurrentDirectory("C:\\");
std::cout << boost::filesystem::current_path() << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

The above program can only be executed in Windows due to the SetCurrentDirectory() function. This function modifies the
current working directory so that both calls to boost::filesystem::current_path() return different results.

There exists a boost::filesystem::initial_path() function returning the directory from within the application has been started.
However, this function depends on additional support from the operating system and thus is not recommended if portability
is required. In this case, the return value of boost::filesystem::current_path() should be saved at the beginning of the
program for future use as recommended by the documentation for Boost.Filesystem.

9.4 File Streams

The C++ standard defines various file streams in the fstream header. These streams certainly do not accept a parameter of
type boost::filesystem::path. Since the Boost.Filesystem library will most likely be included in the Technical Report 2 of the
C++ standard, the file streams will be extended by corresponding constructors though. In order to currently work with file
streams and path information of type boost::filesystem::path, the header boost/filesystem/fstream.hpp can be accessed. It
provides the required additions to file streams that will be added to the C++ standard in the future based on the Technical
Report 2.

#include <boost/filesystem/fstream.hpp>
#include <iostream>
int main()
{
boost::filesystem::path p("test.txt");
boost::filesystem::ofstream ofs(p);
ofs << "Hello, world!" << std::endl;
}

Download source code

Not only the constructors but also the overloaded open() methods accept parameters of type boost::filesystem::path.

9.5 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Create a program that creates an absolute path for a file named data.txt that resides in a directory one level above
the current working directory of the application. For example, if the program is executed from within C:\Program
Files\Test , it should display C:\Program Files\data.txt accordingly.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter10:
Chapter 10: Date
Date andand
TimeTime
Chapter 11: Serialization

Chapter 10: Date and Time


Table of Contents 10.1 General
10.2 Calendar Dates
10.3 Location-independent Times
10.4 Location-dependent Times
10.5 Formatted Input and Output
10.6 Exercises

This book is licensed under a Creative Commons License.

10.1 General

The library Boost.DateTime can be used to process time data such as calendar dates and times. In addition,
Boost.DateTime provides extensions to account for time zones as well as supporting formatted input and output of calendar
dates and times. This chapter covers the individual pieces of Boost.DateTime.

10.2 Calendar Dates

Boost.DateTime only supports calendar dates based on the Gregorian calendar which in general is not a problem since it is
the most widely-used calendar. If a meeting with someone from a different country is arranged for January 5, 2010, it can
be expected that there is no need to advise the person that the date is based on the Gregorian calendar.

The Gregorian calendar was introduced by Pope Gregory XIII in 1582. Strictly speaking, Boost.DateTime supports calendar
dates for the years 1400 to 9999 which means that support goes back beyond the year 1582. Therefore, Boost.DateTime
can be used for any calendar date after the year 1400 when converted to the Gregorian calendar. If older years are
required, a different library must be used instead.

Classes and functions to process calendar dates are offered within the namespace boost::gregorian defined in
boost/date_time/gregorian/gregorian.hpp. To create a date, the boost::gregorian::date class is used.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d(2010, 1, 30);
std::cout << d.year() << std::endl;
std::cout << d.month() << std::endl;
std::cout << d.day() << std::endl;
std::cout << d.day_of_week() << std::endl;
std::cout << d.end_of_month() << std::endl;
}

Download source code

boost::gregorian::date offers multiple constructors to manipulate the date creation. The most basic constructor takes a
year, a month and a day as its arguments. If an invalid value is given, an exception of type boost::gregorian::bad_year,
boost::gregorian::bad_month or boost::gregorian::bad_day_of_month, all derived from std::out_of_range, is thrown.

As shown in the example, there are many methods provided to access a date. While methods such as year(), month() and
day() access the initial values used for initialization, methods like day_of_week() and end_of_month() specifically calculate
values.

Whilst the constructor of boost::gregorian::date takes values for the year, month and day to set a date, calling the
month() method actually displays Jan while calling the day_of_week() displays Sat . These are no regular numeric values but
rather values of type boost::gregorian::date::month_type and boost::gregorian::date::day_of_week_type, respectively.
Nonetheless, Boost.DateTime offers comprehensive support for formatted input and output to adjust the above output from
Jan to 1 .

Please note that an invalid date is created by the default constructor of boost::gregorian::date. Such an invalid date can be
created explicitly by passing boost::date_time::not_a_date_time as the single argument to the constructor.

Besides calling a constructor directly, an object of type boost::gregorian::date can also be created via free-standing
functions and methods of other objects.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d = boost::gregorian::day_clock::universal_day();
std::cout << d.year() << std::endl;
std::cout << d.month() << std::endl;
std::cout << d.day() << std::endl;
d = boost::gregorian::date_from_iso_string("20100131");
std::cout << d.year() << std::endl;
std::cout << d.month() << std::endl;
std::cout << d.day() << std::endl;
}

Download source code

This example utilizes the boost::gregorian::day_clock class which is a clock returning the current date. The universal_day()
returns a UTC date that is independent of time zones and daylight savings. UTC is the international abbreviation for the
universal time. boost::gregorian::day_clock also provides a method named local_day() which takes the local settings into
account. To retrieve the current date within the local time zone, local_day() must be used.
The namespace boost::gregorian contains many additional free-standing functions to convert a date stored in a string to an
object of type boost::gregorian::date. The example actually converts a date given in ISO 8601 format via the
boost::gregorian::date_from_iso_string() function. Other functions such as boost::gregorian::from_simple_string() and
boost::gregorian::from_us_string() are available as well.

While boost::gregorian::date marks a specific point in time, boost::gregorian::date_duration rather denotes a duration.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d1(2008, 1, 31);
boost::gregorian::date d2(2008, 8, 31);
boost::gregorian::date_duration dd = d2 - d1;
std::cout << dd.days() << std::endl;
}

Download source code

Since boost::gregorian::date overloads the operator-() operator, two points in time can be subtracted as shown above. The
return value is of type boost::gregorian::date_duration and marks the duration between the two dates.

The most important method offered by boost::gregorian::date_duration is days() which returns the number of days the
duration consists of.

Objects of type boost::gregorian::date_duration can also be explicitly created by passing the number of days as the single
argument to the constructor. To create a duration that involves weeks, months or years, boost::gregorian::weeks,
boost::gregorian::months and boost::gregorian::years can be used accordingly.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date_duration dd(4);
std::cout << dd.days() << std::endl;
boost::gregorian::weeks ws(4);
std::cout << ws.days() << std::endl;
boost::gregorian::months ms(4);
std::cout << ms.number_of_months() << std::endl;
boost::gregorian::years ys(4);
std::cout << ys.number_of_years() << std::endl;
}

Download source code

Neither boost::gregorian::months nor boost::gregorian::years allow to determine the number of days since months and
years vary in length. Nonetheless, the usage of these classes can still make sense as shown in the following example.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d(2009, 1, 31);
boost::gregorian::months ms(1);
boost::gregorian::date d2 = d + ms;
std::cout << d2 << std::endl;
boost::gregorian::date d3 = d2 - ms;
std::cout << d3 << std::endl;
}

Download source code

The application adds one month to the given date of January 31, 2009 which results in d2 being February 28, 2009. In the
next step, one month is subtracted and d3 becomes January 31, 2009 again. As shown, point in times as well as durations
can be used in calculations. However, the specifics need to be taken into account in these scenarios. For example, starting
at the last day of a month, boost::gregorian::months always arrives at the last day of a different month if jumped forwards
or backwards which can lead to surprises.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d(2009, 1, 30);
boost::gregorian::months ms(1);
boost::gregorian::date d2 = d + ms;
std::cout << d2 << std::endl;
boost::gregorian::date d3 = d2 - ms;
std::cout << d3 << std::endl;
}

Download source code

This example is identical to the previous one with the exception of d being initialized with January 30, 2009. Even though
this is not the last day in January, jumping forward by one month results in d2 becoming February 28, 2009 since there is
no February 30. However, when jumping backwards by one month again, d3 this time actually becomes January 31, 2009!
Since February 28, 2009 is the last day in the month, jumping backwards actually returns to the last day in January.

If that behavior is too confusing, it can be modified by revoking the definition of the
BOOST_DATE_TIME_OPTIONAL_GREGORIAN_TYPES macro. After that, the boost::gregorian::weeks,
boost::gregorian::months and boost::gregorian::years classes are no longer available. The only class left is
boost::gregorian::date_duration which simply jumps forward and backwards by a specified number of days so that
unexpected results are no longer possible.

While boost::gregorian::date_duration works with durations, boost::gregorian::date_period offers support for ranges
between two dates.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d1(2009, 1, 30);
boost::gregorian::date d2(2009, 10, 31);
boost::gregorian::date_period dp(d1, d2);
boost::gregorian::date_duration dd = dp.length();
std::cout << dd.days() << std::endl;
}

Download source code

Two arguments of type boost::gregorian::date specifying the beginning and end dates can be passed to the constructor of
boost::gregorian::date_period. Alternatively, the beginning date and a duration of type boost::gregorian::date_duration can
be specified. Please note that the day before the end date is actually the last day of the period which is important in order
to understand the output of the following example.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d1(2009, 1, 30);
boost::gregorian::date d2(2009, 10, 31);
boost::gregorian::date_period dp(d1, d2);
std::cout << dp.contains(d1) << std::endl;
std::cout << dp.contains(d2) << std::endl;
}

Download source code

The application checks for a specific date within the period using the contains() method. Even though both d1 and d2 were
passed to the constructor of boost::gregorian::date_period, contains() returns true only the first time. Since the end date
is not part of the period, contains() returns false if called with d2.

boost::gregorian::date_period offers additional methods to e.g. move a period or to calculate the intersection of two
overlapping periods.

Besides classes for date, durations and periods, Boost.DateTime provides iterators as well as different useful free-standing
functions as shown in the following example.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::gregorian::date d(2009, 1, 5);
boost::gregorian::day_iterator it(d);
std::cout << *++it << std::endl;
std::cout << boost::date_time::next_weekday(*it,
boost::gregorian::greg_weekday(boost::date_time::Friday)) << std::endl;
}

Download source code


In order to jump forward or backward by a day from a specific date, the iterator boost::gregorian::day_iterator can be
used. With boost::gregorian::week_iterator, boost::gregorian::month_iterator and boost::gregorian::year_iterator,
additional iterators are provided to jump by weeks, months or years.

The example also uses the boost::date_time::next_weekday() which returns the date of the next weekday based on a
given date. The above application displays 2009-Jan-09 since this is the first Friday following January 6, 2009.

10.3 Location-independent Times

While boost::gregorian::date creates a date, boost::posix_time::ptime is used to define a location-independent time.


boost::posix_time::ptime accesses boost::gregorian::date but stores a time in addition.

In order to use boost::posix_time::ptime the header boost/date_time/posix_time/posix_time.hpp needs to be included.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12,
0, 0));
boost::gregorian::date d = pt.date();
std::cout << d << std::endl;
boost::posix_time::time_duration td = pt.time_of_day();
std::cout << td << std::endl;
}

Download source code

To initialize an object of type boost::posix_time::ptime, a date of type boost::gregorian::date and a duration of type
boost::posix_time::time_duration is passed as the first and second argument to the constructor. The three arguments
passed to the constructor of boost::posix_time::time_duration determine the time. The above application specifies 12 PM
on January 5, 2009 as the point in time.

In order to query date and time, the date() and time_of_day() methods can be used.

Just like the default constructor of boost::gregorian::date creates an invalid date, a time of type boost::posix_time::ptime
is also invalid if the default constructor is used. An invalid time can also be created explicitly by passing
boost::date_time::not_a_date_time to the constructor.

Similar to creating calendar dates of type boost::gregorian::date via the use of free-standing functions or methods of
different objects, Boost.DateTime offers corresponding free-standing functions and objects to create times.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime pt = boost::posix_time::second_clock::universal_time();
std::cout << pt.date() << std::endl;
std::cout << pt.time_of_day() << std::endl;
pt = boost::posix_time::from_iso_string("20090105T120000");
std::cout << pt.date() << std::endl;
std::cout << pt.time_of_day() << std::endl;
}

Download source code

The boost::posix_time::second_clock class represents a clock returning the current time. The universal_time() method
returns the UTC time as shown in the above example. If local time is preferred, local_time() must be used.

Boost.DateTime offers an additional class named boost::posix_time::microsec_clock that returns the current time including
microseconds in case a higher resolution is required.

To convert a point in time stored in a string to an object of type boost::posix_time::ptime, free-standing functions such as
boost::posix_time::from_iso_string() are provided which expects the point in time to be stored in the ISO 8601 format.

In addition to boost::posix_time::ptime, Boost.DateTime also offers the boost::posix_time::time_duration class that


specifies a duration. This class has been mentioned before since the constructor of boost::posix_time::ptime actually
expects an object of type boost::posix_time::time_duration as its second argument. Nonetheless,
boost::posix_time::time_duration can certainly be used independently as well.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
int main()
{
boost::posix_time::time_duration td(16, 30, 0);
std::cout << td.hours() << std::endl;
std::cout << td.minutes() << std::endl;
std::cout << td.seconds() << std::endl;
std::cout << td.total_seconds() << std::endl;
}

Download source code

hours(), minutes() and seconds() all return values that are passed to the constructor while methods such as
total_seconds(), returning the total number of seconds, provide one with additional information in a simple way.

Random values can be legally passed to boost::posix_time::time_duration since no upper limit such as 24 hours exists.

As with calendar dates, calculations can also be performed with points in time and durations.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12,
0, 0));
boost::posix_time::ptime pt2(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(18,
30, 0));
boost::posix_time::time_duration td = pt2 - pt1;
std::cout << td.hours() << std::endl;
std::cout << td.minutes() << std::endl;
std::cout << td.seconds() << std::endl;
}

Download source code

If two times of type boost::posix_time::ptime are subtracted from each other, the result is an object of type
boost::posix_time::time_duration specifying the duration between the two points.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12,
0, 0));
boost::posix_time::time_duration td(6, 30, 0);
boost::posix_time::ptime pt2 = pt1 + td;
std::cout << pt2.time_of_day() << std::endl;
}

Download source code

As shown in the example, a duration can be added to a specific point in time resulting in a new point in time. The above
application writes 18:30:00 to the standard output stream.
As one may have been noticed, Boost.DateTime uses the same concepts for both calendar dates and times. Just like there
are classes for times and durations, there is also one for periods. For calendar dates, this class is
boost::gregorian::date_period; for times it is boost::posix_time::time_period. Both classes expect two arguments being
passed to the constructor: boost::gregorian::date_period expects two calendar dates while boost::posix_time::time_period
expects two times.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12,
0, 0));
boost::posix_time::ptime pt2(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(18,
30, 0));
boost::posix_time::time_period tp(pt1, pt2);
std::cout << tp.contains(pt1) << std::endl;
std::cout << tp.contains(pt2) << std::endl;
}

Download source code

In general boost::posix_time::time_period works exactly like boost::gregorian::date_period. It provides a method named


contains() which returns true for every point in time within the period. Since the end time, passed to the constructor of
boost::posix_time::time_period, is not part of the period, above example returns false for the second call of contains().

boost::posix_time::time_period also offers additional methods such as intersection() and merge() to calculate the
intersection of two overlapping periods or to merge two intersecting periods, respectively.

Finally, the iterator boost::posix_time::time_iterator is introduced to iterate over points in time.

#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12,
0, 0));
boost::posix_time::time_iterator it(pt, boost::posix_time::time_duration(6, 30, 0));
std::cout << *++it << std::endl;
std::cout << *++it << std::endl;
}

Download source code

The application uses the iterator it to jump forward 6.5 hours starting at time pt. Since the iterator is incremented twice,
the corresponding output is 2009-Jan-05 18:30:00 and 2009-Jan-06 01:00:00 .

10.4 Location-dependent Times

Unlike the location-independent times introduced in the previous section, location-dependent times actually account for
time zones. For this purpose, Boost.DateTime offers the boost::local_time::local_date_time class, defined in
boost/date_time/local_time/local_time.hpp, which uses boost::local_time::posix_time_zone to store time zone information.

#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>
int main()
{
boost::local_time::time_zone_ptr tz(new boost::local_time::posix_time_zone("CET+1"));
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12,
0, 0));
boost::local_time::local_date_time dt(pt, tz);
std::cout << dt.utc_time() << std::endl;
std::cout << dt << std::endl;
std::cout << dt.local_time() << std::endl;
std::cout << dt.zone_name() << std::endl;
}

Download source code

The constructor of boost::local_time::local_date_time expects an object of type boost::posix_time::ptime as its first


argument as well as an object of type boost::local_time::time_zone_ptr as its second. This is merely a type definition for
boost::shared_ptr<boost::local_time::posix_time_zone>. In other words, no object of type
boost::local_time::posix_time_zone is passed but rather a smart pointer pointing to one. This allows multiple objects of
type boost::local_time::local_date_time to share time zone information. Only if the last object is destroyed, the
corresponding object representing the time zone is automatically released.

To create an object of type boost::local_time::posix_time_zone, a string describing the time zone is passed to the
constructor as the single argument. The above example specifies Central Europe as the time zone: CET is the abbreviation
for Central European Time. Since CET is one hour ahead of UTC, the deviation is denoted as +1 accordingly.
Boost.DateTime is not able to interpret abbreviations for time zones and thus does not know the meaning of CET.
Therefore, the deviation must always be provided in hours; passing +0 means no deviation.

When executed, the application will write 2009-Jan-05 12:00:00 , 2009-Jan-05 13:00:00 CET , 2009-Jan-05 13:00:00 and CET to the
standard output stream. Values used to initialize objects of type boost::posix_time::ptime and
boost::local_time::local_date_time always relate to the UTC time zone by default. Only if an object of type
boost::local_time::local_date_time is written to the standard output stream or a call to the local_time() method is made,
the deviation in hours is used for calculating the local time.

#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>
int main()
{
boost::local_time::time_zone_ptr tz(new boost::local_time::posix_time_zone("CET+1"));
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12,
0, 0));
boost::local_time::local_date_time dt(pt, tz);
std::cout << dt.local_time() << std::endl;
boost::local_time::time_zone_ptr tz2(new boost::local_time::posix_time_zone("EET+2"));
std::cout << dt.local_time_in(tz2).local_time() << std::endl;
}

Download source code

By using the local_time() method, the deviation for the time zone is actually respected. In order to calculate the CET time,
one hour needs to be added to the UTC time of 12 PM stored in dt since CET is one hour ahead of UTC. local_time() writes
2009-Jan-05 13:00:00 to the standard output stream accordingly.

In contrast, the local_time_in() method interprets the time stored in dt as being in the time zone passed as the argument.
This means that 12 PM UTC equals 2 PM EET which stands for Eastern European Time and is two hours ahead of UTC.

Finally, location-dependent periods are offered by Boost.DateTime via the boost::local_time::local_time_period class.

#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>
int main()
{
boost::local_time::time_zone_ptr tz(new boost::local_time::posix_time_zone("CET+0"));
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12,
0, 0));
boost::local_time::local_date_time dt1(pt1, tz);
boost::posix_time::ptime pt2(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(18,
0, 0));
boost::local_time::local_date_time dt2(pt2, tz);
boost::local_time::local_time_period tp(dt1, dt2);
std::cout << tp.contains(dt1) << std::endl;
std::cout << tp.contains(dt2) << std::endl;
}

Download source code

The constructor of boost::local_time::local_time_period expects two arguments of type boost::local_time::local_date_time.


As with the other data types provided for periods, the second argument, representing the end time, is not part of the
actual period. With the help of methods such as contains(), intersection(), merge() and others, periods can be processed
with boost::local_time::local_time_period accordingly.

10.5 Formatted Input and Output

Any example in this chapter provided results such as 2009-Jan-07 once executed. Some people may actually prefer a
different format to display the results. Boost.DateTime allows to format calendar dates and times via the
boost::date_time::date_facet and boost::date_time::time_facet classes.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <locale>
int main()
{
boost::gregorian::date d(2009, 1, 7);
boost::gregorian::date_facet *df = new boost::gregorian::date_facet("%A, %d %B %Y");
std::cout.imbue(std::locale(std::cout.getloc(), df));
std::cout << d << std::endl;
}

Download source code

Boost.DateTime uses the concept of locales known from the C++ standard introduced in a nutshell in Chapter5, String
Handling. To format a calendar date, an object of type boost::date_time::date_facet must be created and installed within a
locale. A string describing the new format is passed to the constructor of boost::date_time::date_facet. The example
passes %A, %d %B %Y specifying that the day of the week is followed by the date with the month written in full:
Wednesday, 07 January 2009 .

Boost.DateTime offers numerous format flags that consist of the percent sign followed by a character. The documentation
of Boost.DateTime contains a complete overview over all supported flags. For example, %A specifies the name of the
weekday.

If the user base of the application is located in Germany or German-speaking countries, it is preferable to display both the
weekday and the month in German rather than in English.

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <locale>
#include <string>
#include <vector>
int main()
{
std::locale::global(std::locale("German"));
std::string months[12] = { "Januar", "Februar", "Mrz", "April", "Mai", "Juni", "Juli", "August",
"September", "Oktober", "November", "Dezember" };
std::string weekdays[7] = { "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag",
"Samstag" };
boost::gregorian::date d(2009, 1, 7);
boost::gregorian::date_facet *df = new boost::gregorian::date_facet("%A, %d. %B %Y");
df->long_month_names(std::vector<std::string>(months, months + 12));
df->long_weekday_names(std::vector<std::string>(weekdays, weekdays + 7));
std::cout.imbue(std::locale(std::cout.getloc(), df));
std::cout << d << std::endl;
}

Download source code

The names for weekdays and months can be changed by passing vectors containing corresponding names to the
long_month_names() and long_weekday_names() methods of the boost::date_time::date_facet class. The above example
now writes Mittwoch, 07. Januar 2009 to the standard output stream.
Boost.DateTime is pretty flexible in regards to formatted input and output. Besides the output classes
boost::date_time::date_facet and boost::date_time::time_facet, the classes boost::date_time::date_input_facet and
boost::date_time::time_input_facet are available for formatted input. All four classes provide many methods to configure
the input and output of the different objects provided by Boost.DateTime. For example, it is possible to specify how periods
of type boost::gregorian::date_period are input and output. Due to the manifold possibilities for formatted input and
output it is essential to review the documentation of Boost.DateTime.

10.6 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Create an application that writes the weekdays for the next Christmas Eve, Christmas Day and the following day to
the standard output stream.

2. Calculate your age in days. The application should determine the current date for the computation automatically.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter11:
Chapter 11: Serialization
Serialization
Chapter 12: Parser

Chapter 11: Serialization


Table of Contents 11.1 General
11.2 Archive
11.3 Pointers and references
11.4 Serialization of class hierarchy objects
11.5 Wrapper functions for optimization
11.6 Exercises

This book is licensed under a Creative Commons License.

11.1 General

The Boost C++ Library Serialization allows to convert objects in a C++ application into a sequence of bytes that can be
saved and loaded again at a later time to restore the objects. Different data formats, including XML, are available that
specify the rules after which the sequence of bytes is generated. All of the formats supported by Boost.Serialization are
proprietary in some respect. For example, the XML format cannot be used to exchange data with other applications that
were not developed in C++ using Boost.Serialization. All data stored in the XML format is geared towards restoring the
same C++ objects previously saved. The solely advantage of the XML format is the better understanding of serialized C++
objects which is helpful during e.g. debugging.

11.2 Archive

The main concept of Boost.Serialization is the archive. An archive is a sequence of bytes representing serialized C++
objects. Objects can be added to an archive to serialize them or be loaded from one, respectively. In order to restore the
same C++ objects previously saved, the same data types are presumed.

The following is a simple example.

#include <boost/archive/text_oarchive.hpp>
#include <iostream>
int main()
{
boost::archive::text_oarchive oa(std::cout);
int i = 1;
oa << i;
}

Download source code

Boost.Serialization provides multiple archive classes such as boost::archive::text_oarchive defined in


boost/archive/text_oarchive.hpp. boost::archive::text_oarchive allows the serialization of objects as a text stream. The
above application writes 22 serialization::archive 5 1 to the standard output stream.
As can be seen, the object oa of type boost::archive::text_oarchive can be used just like a stream to serialize a variable
via <<. Nonetheless, archives should not be considered as regular streams storing arbitrary data. In order to restore the
data at a later point, it is necessary to use the same data types in the same order they were previously saved. The
following example serializes and restores the variable of type int.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <fstream>
void save()
{
std::ofstream file("archiv.txt");
boost::archive::text_oarchive oa(file);
int i = 1;
oa << i;
}
void load()
{
std::ifstream file("archiv.txt");
boost::archive::text_iarchive ia(file);
int i = 0;
ia >> i;
std::cout << i << std::endl;
}
int main()
{
save();
load();
}

Download source code

While boost::archive::text_oarchive is used to serialize data as a text stream, boost::archive::text_iarchive is used to


restore data from such a text stream. In order to use the class, the header file boost/archive/text_iarchive.hpp must be
included.

Constructors of archives expect an input or output stream as the argument. The stream is used to serialize or to restore
data, respectively. While above application accesses a file, other streams such as a stringstream could be used
alternatively.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
void save()
{
boost::archive::text_oarchive oa(ss);
int i = 1;
oa << i;
}
void load()
{
boost::archive::text_iarchive ia(ss);
int i = 0;
ia >> i;
std::cout << i << std::endl;
}
int main()
{
save();
load();
}

Download source code

The application also writes 1 to the standard output stream. However, opposed to the previous one, data is serialized using
a stringstream instead.

So far, primitive data types have been serialized. The following example shows how to serialize objects of user defined data
types.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}
int age_;
};
void save()
{
boost::archive::text_oarchive oa(ss);
person p(31);
oa << p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
}
int main()
{
save();
load();
}

Download source code

In order to serialize objects of user defined data types, a method named serialize() must be defined which is called if the
object is serialized to or restored from a byte stream. Since serialize() is used for both serializing and restoring,
Boost.Serialization offers the operator & in addition to the << and >> ones. If used, there is no longer the need to
distinguish between serializing and restoring within the serialize() method.

serialize() is automatically called any time an object is serialized or restored. It should never be called explicitly and thus
should be declared as private. In this case, the class boost::serialization::access must be declared as friend which allows
Boost.Serialization to access the method.

There may be situations that do not allow to modify an existing class in order to add the serialize() method. This is for
example true for classes from the C++ standard or any other library.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
friend void serialize(Archive &ar, person &p, const unsigned int version);
int age_;
};
template <typename Archive>
void serialize(Archive &ar, person &p, const unsigned int version)
{
ar & p.age_;
}
void save()
{
boost::archive::text_oarchive oa(ss);
person p(31);
oa << p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
}
int main()
{
save();
load();
}

Download source code

In order to serialize data types that cannot be modified, the free-standing function serialize() can be defined as shown in
the above example. The function expects a reference to an object of the corresponding data type as its second argument.
If the data type to be serialized contains private properties which cannot be accessed via public methods, things get more
complicated. In this case, the data type may need to be modified. The serialize() function in the above application would
not be able to access the age_ property without the friend declaration.

Fortunately, Boost.Serialization provides corresponding serialize() functions for many classes of the C++ standard. To
serialize objects based on C++ standard classes, additional header files need to be included.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <iostream>
#include <sstream>
#include <string>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age, const std::string &name)
: age_(age), name_(name)
{
}
int age() const
{
return age_;
}
std::string name() const
{
return name_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
friend void serialize(Archive &ar, person &p, const unsigned int version);
int age_;
std::string name_;
};
template <typename Archive>
void serialize(Archive &ar, person &p, const unsigned int version)
{
ar & p.age_;
ar & p.name_;
}
void save()
{
boost::archive::text_oarchive oa(ss);
person p(31, "Boris");
oa << p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
std::cout << p.name() << std::endl;
}
int main()
{
save();
load();
}

Download source code

The example extends the person class by a name of type std::string. In order to serialize this property, the header file
boost/serialization/string.hpp must be included which offers the appropriate free-standing serialize() function.

As mentioned before, Boost.Serialization defines serialize() functions for many classes of the C++ standard. These are
defined in header files that carry the same name as the corresponding header files from the C++ standard. In order to
serialize objects of type std::string, the header file boost/serialization/string.hpp must be included. For serializing an object
of type std::vector, the header file boost/serialization/vector.hpp must be used instead. It is therefore fairly obvious which
header file must be included in any given scenario.

One argument of serialize(), which has been ignored so far, is version. This argument is relevant if archives should be
forward compatible to support future versions of the given application. The next example considers archives of the person
class as being forward compatible. Since the original version of person did not contain any name, the new version of
person still should be able to manage old archives created without the name.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <iostream>
#include <sstream>
#include <string>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age, const std::string &name)
: age_(age), name_(name)
{
}
int age() const
{
return age_;
}
std::string name() const
{
return name_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
friend void serialize(Archive &ar, person &p, const unsigned int version);
int age_;
std::string name_;
};
template <typename Archive>
void serialize(Archive &ar, person &p, const unsigned int version)
{
ar & p.age_;
if (version > 0)
ar & p.name_;
}
BOOST_CLASS_VERSION(person, 1)
void save()
{
boost::archive::text_oarchive oa(ss);
person p(31, "Boris");
oa << p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
std::cout << p.name() << std::endl;
}
int main()
{
save();
load();
}

Download source code

The macro BOOST_CLASS_VERSION is used to specify a version number to a class. The version number for the person
class in the above application is set to 1. If BOOST_CLASS_VERSION is not used, the version number is 0 by default.
The version number is stored within the archive and thus is part of it. While the version number specified for a particular
class via the BOOST_CLASS_VERSION macro is used during serialization, the version argument of serialize() is set to the
value stored in the archive when the object is restored. If the new version of person accesses an archive containing an
object serialized with the old version, the name_ property would not be restored since the old version did not contain such
a property. Forward compatible archives are therefore supported by Boost.Serialization via this mechanism.

11.3 Pointers and references

Boost.Serialization can also serialize pointers and references. Since a pointer stores the address of an object, serializing the
address certainly does not make much sense. While serializing pointers and references, the object referenced is
automatically serialized instead.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}
int age_;
};
void save()
{
boost::archive::text_oarchive oa(ss);
person *p = new person(31);
oa << p;
std::cout << std::hex << p << std::endl;
delete p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
person *p;
ia >> p;
std::cout << std::hex << p << std::endl;
std::cout << p->age() << std::endl;
delete p;
}
int main()
{
save();
load();
}

Download source code

The above application creates a new object of type person using new and assigns it to the pointer p. The pointer - not *p -
is then serialized. Boost.Serialization automatically serializes the object itself as referenced by p and not the address of the
object.

If the archive is restored, p does not necessarily refer to the same address. A new object is created and its address is
assigned to p instead. Boost.Serialization only guarantees that the object is identical to the one serialized, not that its
address is the same.

Since modern C++ uses smart pointers in connection with dynamically allocated memory, Boost.Serialization provides
support accordingly.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/scoped_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}
int age_;
};
void save()
{
boost::archive::text_oarchive oa(ss);
boost::scoped_ptr<person> p(new person(31));
oa << p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
boost::scoped_ptr<person> p;
ia >> p;
std::cout << p->age() << std::endl;
}
int main()
{
save();
load();
}

Download source code

The example uses the smart pointer boost::scoped_ptr to manage a dynamically allocated object of type person. In order
to serialize such a pointer, the header file boost/serialization/scoped_ptr.hpp must be included.

In case a smart pointer of type boost::shared_ptr should be serialized, the header file boost/serialization/shared_ptr.hpp
must be used instead.

The following application now uses a reference in place of a pointer.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}
int age_;
};
void save()
{
boost::archive::text_oarchive oa(ss);
person p(31);
person &pp = p;
oa << pp;
}
void load()
{
boost::archive::text_iarchive ia(ss);
person p;
person &pp = p;
ia >> pp;
std::cout << pp.age() << std::endl;
}
int main()
{
save();
load();
}

Download source code

As shown, Boost.Serialization can also serialize references without any issue. Just like with pointers, the referenced object
is serialized automatically.

11.4 Serialization of class hierarchy objects


In order to serialize objects based on class hierarchies, the child classes must access the boost::serialization::base_object()
function inside the serialize() method. This function guarantees that inherited properties of base classes are correctly
serialized as well. The following example shows a class named developer which is derived from person.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <iostream>
#include <sstream>
#include <string>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}
int age_;
};
class developer
: public person
{
public:
developer()
{
}
developer(int age, const std::string &language)
: person(age), language_(language)
{
}
std::string language() const
{
return language_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<person>(*this);
ar & language_;
}
std::string language_;
};
void save()
{
boost::archive::text_oarchive oa(ss);
developer d(31, "C++");
oa << d;
}
void load()
{
boost::archive::text_iarchive ia(ss);
developer d;
ia >> d;
std::cout << d.age() << std::endl;
std::cout << d.language() << std::endl;
}
int main()
{
save();
load();
}

Download source code

Both person and developer contain a private serialize() method allowing objects based on either class to be serialized.
Since developer is derived from person, the serialize() method must ensure that properties inherited from person are also
serialized.

Inherited properties are serialized by accessing the base class inside the serialize() method of the child class using
boost::serialization::base_object(). It is mandatory to use this function over e.g. static_cast since only
boost::serialization::base_object() ensures correct serialization.

Addresses of objects dynamically created can be assigned to pointers of the corresponding base class type. The following
example shows that Boost.Serialization still serializes them correctly.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
#include <sstream>
#include <string>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
virtual int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}
int age_;
};
class developer
: public person
{
public:
developer()
{
}
developer(int age, const std::string &language)
: person(age), language_(language)
{
}
std::string language() const
{
return language_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<person>(*this);
ar & language_;
}
std::string language_;
};
BOOST_CLASS_EXPORT(developer)
void save()
{
boost::archive::text_oarchive oa(ss);
person *p = new developer(31, "C++");
oa << p;
delete p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
person *p;
ia >> p;
std::cout << p->age() << std::endl;
delete p;
}
int main()
{
save();
load();
}

Download source code

The application creates an object of type developer inside the save() function and assigns it to a pointer of type person*
which in turn is serialized via << accordingly.

As mentioned in the previous section, the referenced object is automatically serialized. In order to have Boost.Serialization
recognize that an object of type developer must be serialized even though the pointer is of type person*, the class
developer needs to be declared accordingly. This is done via the BOOST_CLASS_EXPORT macro defined in
boost/serialization/export.hpp. Since the type developer does not appear in the pointer definition, Boost.Serialization would
not be able to serialize an object of type developer correctly without the macro.

The macro BOOST_CLASS_EXPORT must be used if objects of child classes should be serialized via a pointer to their
corresponding base class.

Because of the static registration, one disadvantage of BOOST_CLASS_EXPORT is the registration of classes that may not
be serialized at all. Boost.Serialization offers a solution for exactly this scenario though.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
#include <sstream>
#include <string>
std::stringstream ss;
class person
{
public:
person()
{
}
person(int age)
: age_(age)
{
}
virtual int age() const
{
return age_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}
int age_;
};
class developer
: public person
{
public:
developer()
{
}
developer(int age, const std::string &language)
: person(age), language_(language)
{
}
std::string language() const
{
return language_;
}
private:
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<person>(*this);
ar & language_;
}
std::string language_;
};
void save()
{
boost::archive::text_oarchive oa(ss);
oa.register_type<developer>();
person *p = new developer(31, "C++");
oa << p;
delete p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
ia.register_type<developer>();
person *p;
ia >> p;
std::cout << p->age() << std::endl;
delete p;
}
int main()
{
save();
load();
}

Download source code

Instead of using the BOOST_CLASS_EXPORT macro, the above application calls the template method register_type()
instead. The type to be registered is passed as the template argument accordingly.

Please note that register_type() must be called both in save() and load().

The advantage of register_type() is that only classes used for serialization must be registered. While developing e.g. a
library, one does not know which classes a developer may use for serialization later on. While the macro
BOOST_CLASS_EXPORT certainly makes it easy, it may register types that are not going to be serialized.

11.5 Wrapper functions for optimization

After understanding how to serialize objects, this section introduces wrapper functions to optimize the serialization process.
By using these functions, objects are kind of marked to allow Boost.Serialization to apply certain optimization techniques.

The following example uses Boost.Serialization without any wrapper function.

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
void save()
{
boost::archive::text_oarchive oa(ss);
boost::array<int, 3> a = { 0, 1, 2 };
oa << a;
}
void load()
{
boost::archive::text_iarchive ia(ss);
boost::array<int, 3> a;
ia >> a;
std::cout << a[0] << ", " << a[1] << ", " << a[2] << std::endl;
}
int main()
{
save();
load();
}

Download source code

The above application creates and writes the text stream 22 serialization::archive 5 0 0 3 0 1 2 to the standard output
stream. Using the wrapper function boost::serialization::make_array(), the output can be shortened to 22
serialization::archive 5 0 1 2 .

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/array.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <sstream>
std::stringstream ss;
void save()
{
boost::archive::text_oarchive oa(ss);
boost::array<int, 3> a = { 0, 1, 2 };
oa << boost::serialization::make_array(a.data(), a.size());
}
void load()
{
boost::archive::text_iarchive ia(ss);
boost::array<int, 3> a;
ia >> boost::serialization::make_array(a.data(), a.size());
std::cout << a[0] << ", " << a[1] << ", " << a[2] << std::endl;
}
int main()
{
save();
load();
}
Download source code

boost::serialization::make_array() expects the address and the length of an array. Since the length is hard-coded, it does
not need to be serialized as part of the object of type boost::array. The function can be used whenever classes such as
boost::array or std::vector contain an array that can be directly serialized. Additional properties that normally would be
serialized are not serialized.

Another wrapper function provided by Boost.Serialization is boost::serialization::make_binary_object(). Similar to


boost::serialization::make_array(), it expects an address and a length. boost::serialization::make_binary_object() is used
solely for binary data without any underlying structure while boost::serialization::make_array() is used for arrays.

11.6 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Develop an application able to serialize and restore arbitrary number of records consisting of the name, the
department and a unique identification number of employees in a file. Records should be displayed on the screen
after restoring them. Use sample records to test the application.

2. Extend the application by storing the birth date for each employee. The application should still be able to restore
records serialized with the older version created in the previous exercise.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter12:
Chapter 12: Parser
Parser
Chapter 13: Containers

Chapter 12: Parser


Table of Contents 12.1 General
12.2 Extended Backus-Naur Form
12.3 Grammar
12.4 Actions
12.5 Exercises

This book is licensed under a Creative Commons License.

12.1 General

Parsers are used to read formats that allow a flexible but potential complicated structure of data. A good example of such
a format is C++ code. The parser of the compiler needs to understand the various language constructs in all possible
combinations of C++ in order to translate them to a binary form.

The major issue while developing parsers is usually the sheer amount of rules by which the corresponding data is
structured. For example, C++ supports so many language constructs that the development of a corresponding parser would
require countless if expressions to recognize any imaginable C++ code as being valid.

The library Boost.Spirit introduced in this chapter turns the tables on developing parsers. Instead translating explicit rules
into code and validating this code using countless if expressions, Boost.Spirit allows to express the rules using the so-called
Extended Backus-Naur Form. Using these rules, Boost.Spirit then can parse a C++ source code file accordingly.

The basic idea of Boost.Spirit is similar to regular expressions. Instead of searching a text for a specific pattern using if
expressions, the pattern is rather specified as a regular expression. The search is then performed by a library such as
Boost.Regex so that the developer does not need to care about the details.

This chapter shows how to use Boost.Spirit to read complicated formats for which regular expressions are no longer
feasible. Since Boost.Spirit is a comprehensive library introducing different concepts, a simple parser for the JSON format is
developed throughout the chapter. JSON is an existing format which is used by e.g. Ajax applications to exchange data
similar to XML between applications that potentially may even run on different platforms.

Even though Boost.Spirit simplifies the development of parsers, no one succeeded to write a C++ parser based on this
library yet. The development of such a parser is still a long-term goal of Boost.Spirit, however, due to the complexity of
the C++ language, has not been achieved so far. Boost.Spirit is currently not well suited for these kind of complex or
binary formats.
12.2 Extended Backus-Naur Form

The Backus-Naur Form, abbreviated BNF, is a language to precisely describe rules and is used in many technical
specifications. For example, many specifications of the numerous Internet protocols, the so-called request for comments,
contain the rules in BNF in addition to annotations in text.

Boost.Spirit supports the Extended Backus-Naur Form (EBNF) which allows to specify rules in a shorter form than BNF
does. The main advantage of EBNF is a shortened and thus simplified notation.

Please note that there are different variations of EBNF which may differ in their syntax. This chapter as well as Boost.Spirit
itself uses the EBNF which syntax resembles the one of regular expressions.

In order to use Boost.Spirit, one needs to understand EBNF accordingly. Most of the time, developers already know EBNF
and therefore select Boost.Spirit to reuse rules previously specified in EBNF. Below is a short introduction to EBNF; for a
quick reference of the syntax used in this chapter and by Boost.Spirit, please refer to the W3C XML specification that
contains a short summary.

digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

Strictly speaking, EBNF denotes rules as production rules. Any number of production rules can be combined to describe a
particular format. The above format consists of only one production rule. It defines a digit that is made up of a number
between 0 and 9.

Definitions such as digit are called nonterminal symbols. The numeric values 0 to 9 in the above definition are called
terminal symbols instead. These symbols do not have any special meaning and can be easily identified since they are
enclosed by double quotes.

All numeric values are connected by the pipe operator which has the same meaning as the || operator in C++: It denotes
an alternative.

Summarized, the production rule specifies that any number between 0 and 9 is a digit.

integer = ("+" | "-")? digit+

The new nonterminal symbol integer consists of at least a digit that can be preceded by a plus or minus sign.

The definition of integer uses a couple of new operators. Parenthesis are used to create partial expressions just like in
mathematics. Other operators can then be applied to these expressions. The question mark denotes that the partial
expression can only be declared either once or not at all.

The plus sign following digit indicates that the corresponding expression must be declared at least once.

This new production rule defines an arbitrary positive or negative integer. While a digit consists of exactly one digit, an
integer can consist of any combination of digits which can also be marked unsigned or signed. Whereas 5 is both a digit
and an integer, +5 is solely an integer. The same applies to 169 or -8 which are also integer only.
More and more complex production rules can be created by simply defining and combining nonterminal symbols.

real = integer "." digit*

While the definition of integer represents integers, the definition of real represents floating-point numbers. The rule is
based on the already defined nonterminal symbols integer and digit separated by a dot. The asterisk after digit specifies
that digits after the dot are optional: There can either be an arbitrary number or none.

Floating-point numbers such as 1.2, -16.99 or even 3. satisfy the definition of real. However, the current definition does
not allow floating-point numbers without a leading zero such as .9.

As mentioned in the beginning of this chapter, a parser for the JSON format is going to be developed using Boost.Spirit.
For this purpose, the rules of the JSON format need to be expressed in EBNF.

object = "{" member ("," member)* "}"

member = string ":" value

string = '"' character* '"'

value = string | number | object | array | "true" | "false" | "null"

number = integer | real

array = "[" value ("," value)* "]"

character = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" |
"t" | "u" | "v" | "w" | "x" | "y" | "z"

The JSON format is based on objects that contain pairs of keys and values enclosed by curly braces. While the keys are
simple strings, values can range from strings, numeric values, arrays, other objects or the literal true, false or null. Strings
are a consecutive character stream enclosed by double quotes. Numeric values can either be integers or floating-point
numbers. Arrays contain values separated by comma that are enclosed by squared brackets.

Please note that the above definition is not complete. On the one hand, the definition of character lacks capital letters as
well as additional characters; on the other hand, JSON supports specifics such as Unicode or control characters. This can be
currently ignored since Boost.Spirit defines frequently used nonterminal symbols such as alphanumeric characters to save
one from typing endless character streams. In addition, a string will be later defined in code as a consecutive stream of
arbitrary characters excluding double quotes. Since double quotes finalize the string, all other characters can be therefore
used within a string. The above EBNF does not express this accordingly since EBNF requires the definition of a nonterminal
symbol for all characters except the ones that should be excluded in order to define an exception.

The following is an example for a JSON format for which above definition applies.

{
"Boris Schling" :
{
"Male": true,
"Programming Languages": [ "C++", "Java", "C#" ],
"Age": 31
}
}

The global object is characterized by the outer curly braces and contains a key-value pair. The key is named "Boris
Schling", the value is a new object that contains multiple key-value pairs. While all the keys are strings, the values are
the literal true, an array containing several strings and a numeric value.

The EBNF rules defined above can now be used to develop a parser using Boost.Spirit that is able to read the above JSON
format.

12.3 Grammar

After defining the rules for the JSON format in EBNF in the previous section, they now need to be used together with
Boost.Spirit somehow. Boost.Spirit actually allows to define the EBNF rules as C++ code by overloading the different
operators used by EBNF.

Please note that the EBNF rules need to be modified slightly in order to create valid C++ code. Symbols that are combined
by a space in EBNF need to be combined using some operator in C++. Additionally, operators such as the asterisk, the
question mark and the plus sign, placed directly behind the corresponding symbol in EBNF, must be placed in front of the
symbol in order to use them as unary operators in C++.

The following shows the EBNF rules for the JSON format expressed in C++ code for Boost.Spirit.

#include <boost/spirit.hpp>
struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
template <typename Scanner>
struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;
definition(const json_grammar &self)
{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | "true" | "false" | "null";
number = real_p;
array = "[" >> value >> *("," >> value) >> "]";
}
const boost::spirit::rule<Scanner> &start()
{
return object;
}
};
};
int main()
{
}

Download source code

To use the different classes of Boost.Spirit, the header boost/spirit.hpp needs to be included. The classes are provided
within the namespace boost::spirit.

In order to create a parser with Boost.Spirit, a so-called grammar must be created which among other things defines the
rules after which the data is structured. In the above example the json_grammar class has been developed which is
derived from the template class boost::spirit::grammar and is instantiated with the name of the class. json_grammar
defines the complete grammar necessary to understand the JSON format.

One important component of the grammar are the rules to read structured data correctly. These rules are defined within
an inner class named definition - this name is mandatory. This class is a template with one argument which is instantiated
with a so-called scanner by Boost.Spirit. A scanner is a concept internally used by Boost.Spirit. Even though it is mandatory
for definition to be a template taking a scanner type as its argument, it is irrelevant for the daily use of Boost.Spirit what
these scanners actually are and why they are defined.

definition must define a method named start() which is called by Boost.Spirit to obtain the complete rules and standards of
the grammar. The return value of this method is a constant reference to boost::spirit::rule that is also a template class
instantiated with the scanner type.

The class boost::spirit::rule is used to define rules. Nonterminal symbols are defined by means of this class. The previously
defined nonterminal symbols object, member, string, value, number and array are all of type boost::spirit::rule.

All of these objects are defined as properties of the definition class which is not mandatory but alleviates the definition
especially if rules reference each other recursively. As seen with the EBNF examples in the previous section, recursive
references are not an issue.

At first glance, the definitions of the rules within the constructor of definition look similar to the production rules of the
EBNF seen in the previous section. This does not come as a surprise though since this is exactly the goal of Boost.Spirit:
To reuse production rules defined in the EBNF.

While the C++ code resembles the rules established in the EBNF, there are certainly small differences in order to write
valid C++. For example, all of the symbols are concatenated via the >> operator. EBNF operators such as the asterisk are
placed in front of the symbols instead of following them. Despite these syntax changes, Boost.Spirit strives to convert
EBNF rules to C++ code without many changes.

The constructor of definition uses two classes provided by Boost.Spirit: boost::spirit::ch_p and boost::spirit::real_p.
Frequently used rules are provided in the form of parsers that can easily be reused. One example is boost::spirit::real_p
which allows storing positive and negative integers and floating-point numbers without the need to define nonterminal
symbols such as digit or real.

boost::spirit::ch_p can be used to create a parser for a single character which is equal to enclosing the character with
double quotes. In the above example, the usage of boost::spirit::ch_p is mandatory since the tilde and asterisk are applied
to the double quote sign. Without the class, the code would read *~"\"" which would be rejected by the compiler as invalid
code.
The tilde actually allows the trick mentioned in the previous section: By prefixing the double quote with the tilde, all
characters except the double quote are accepted.

After the rules for identifying the JSON format are defined, the following example shows how to use them.

#include <boost/spirit.hpp>
#include <fstream>
#include <sstream>
#include <iostream>
struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
template <typename Scanner>
struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;
definition(const json_grammar &self)
{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | "true" | "false" | "null";
number = real_p;
array = "[" >> value >> *("," >> value) >> "]";
}
const boost::spirit::rule<Scanner> &start()
{
return object;
}
};
};
int main(int argc, char *argv[])
{
std::ifstream fs(argv[1]);
std::ostringstream ss;
ss << fs.rdbuf();
std::string data = ss.str();
json_grammar g;
boost::spirit::parse_info<> pi = boost::spirit::parse(data.c_str(), g, boost::spirit::space_p);
if (pi.hit)
{
if (pi.full)
std::cout << "parsing all data successfully" << std::endl;
else
std::cout << "parsing data partially" << std::endl;
std::cout << pi.length << " characters parsed" << std::endl;
}
else
std::cout << "parsing failed; stopped at '" << pi.stop << "'" << std::endl;
}
Download source code

Boost.Spirit offers a free-standing function named boost::spirit::parse(). By creating an instance of a grammar, a parser is
created accordingly which is passed to boost::spirit::parse() as the second argument. The first argument denotes the text
to be parsed while the third argument is a parser indicating which characters should be skipped in the given text. To skip
spaces, an object of type boost::spirit::space_p is passed as the third argument. This simply means that an arbitrary
number of spaces is allowed between the data to be captured - in other words, everywhere the >> operator was applied in
the rules. Tabulators and line breaks are included which allows for a more flexible notation of data formats.

boost::spirit::parse() returns an object of type boost::spirit::parse_info that offers four properties indicating whether or
not the text was successfully parsed. The hit property is set to true if the text was successfully parsed. If all characters in
the text were parsed without e.g. remaining spaces at the end, full is also set to true. Only if hit equals true, length is
valid and contains the number of characters parsed successfully.

The length property must not be accessed if the text could not be parsed successfully. In this case, the stop property
allows to access the text location where parsing stopped. While stop can also be accessed if the text was parsed
successfully, it does not make much sense since it will point behind the parsed text in this case.

12.4 Actions

So far, one knows how to define a grammar in order to obtain a new parser that can be used to identify whether a specific
text is structured according to the rules of the grammar. However, the data format still is not interpreted at this point since
the individual data read from a structured format such as JSON are not processed further.

In order to process data satisfying a specific rule as identified by the parser, actions are used. Actions are functions that
are associated with rules. If the parser identifies data satisfying a specific rule, the associated action is executed, passing
the data to be processed accordingly as shown in the following example.

#include <boost/spirit.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
struct print
{
void operator()(const char *begin, const char *end) const
{
std::cout << std::string(begin, end) << std::endl;
}
};
template <typename Scanner>
struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;
definition(const json_grammar &self)
{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string[print()] >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | "true" | "false" | "null";
number = real_p;
array = "[" >> value >> *("," >> value) >> "]";
}
const boost::spirit::rule<Scanner> &start()
{
return object;
}
};
};
int main(int argc, char *argv[])
{
std::ifstream fs(argv[1]);
std::ostringstream ss;
ss << fs.rdbuf();
std::string data = ss.str();
json_grammar g;
boost::spirit::parse_info<> pi = boost::spirit::parse(data.c_str(), g, boost::spirit::space_p);
if (pi.hit)
{
if (pi.full)
std::cout << "parsing all data successfully" << std::endl;
else
std::cout << "parsing data partially" << std::endl;
std::cout << pi.length << " characters parsed" << std::endl;
}
else
std::cout << "parsing failed; stopped at '" << pi.stop << "'" << std::endl;
}

Download source code

Actions are implemented as functions or function objects. The latter are beneficial if the action should be initialized or
maintain state information between repeated executions. The above example implements the action as a function object.

The class print is a function object which writes data to the standard output stream. When called, the overloaded
operator()() operator receives a pointer to the beginning and end of the data as identified by the rules executing the
particular action.

The example associates the action with the nonterminal symbol string which appears as the first symbol after member. An
instance of type print is passed to the nonterminal symbol string inside squared brackets. As string represents the key
within key-value pairs of JSON objects, the overloaded operator()() operator of class print is called for every discovered
key which simply writes the key to the standard output stream.

It is now possible to define an arbitrary number of actions or to associate them with an arbitrary number of symbols. In
order to associate an action with a literal, a parser must be specified explicitly. This is no different from the definition of
the nonterminal symbol string specifying the boost::spirit::ch_p class. The following example uses the boost::spirit::str_p
class to associate an object of type print with the literal true.

#include <boost/spirit.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
struct print
{
void operator()(const char *begin, const char *end) const
{
std::cout << std::string(begin, end) << std::endl;
}
void operator()(const double d) const
{
std::cout << d << std::endl;
}
};
template <typename Scanner>
struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;
definition(const json_grammar &self)
{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string[print()] >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | str_p("true")[print()] | "false" | "null";
number = real_p[print()];
array = "[" >> value >> *("," >> value) >> "]";
}
const boost::spirit::rule<Scanner> &start()
{
return object;
}
};
};
int main(int argc, char *argv[])
{
std::ifstream fs(argv[1]);
std::ostringstream ss;
ss << fs.rdbuf();
std::string data = ss.str();
json_grammar g;
boost::spirit::parse_info<> pi = boost::spirit::parse(data.c_str(), g, boost::spirit::space_p);
if (pi.hit)
{
if (pi.full)
std::cout << "parsing all data successfully" << std::endl;
else
std::cout << "parsing data partially" << std::endl;
std::cout << pi.length << " characters parsed" << std::endl;
}
else
std::cout << "parsing failed; stopped at '" << pi.stop << "'" << std::endl;
}

Download source code

In addition, the example associates an action with boost::spirit::real_p. While most parsers pass a pointer to the beginning
and end of the identified data, boost::spirit::real_p passes the discovered number as double instead. This certainly makes
processing of numbers much easier since they do not need to be converted explicitly. In order to pass a value of type
double to the action, a corresponding overloaded operator()() operator has been added to print.

Besides the parsers introduced in this chapter such as boost::spirit::str_p or boost::spirit::real_p, Boost.Spirit offers many
more. For example, boost::spirit::regex_p is helpful if regular expressions should be used. In addition, parsers to verify
conditions or execute loops exist as well. This helps creating dynamic parsers which process data differently depending on
conditions. In order to get an overview over the utilities provided by Boost.Spirit, one should take a look at its
documentation.

12.5 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Develop a calculator that can add and subtract arbitrary integers and floating-point numbers. The calculator should
accept input such as =-4+8 + 1.5 and display 5.5 as the result accordingly.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter13:
Chapter 13: Containers
Containers
Chapter 14: Data Structures

Chapter 13: Containers


Table of Contents 13.1 General
13.2 Boost.Array
13.3 Boost.Unordered
13.4 Boost.MultiIndex
13.5 Boost.Bimap
13.6 Exercises

This book is licensed under a Creative Commons License.

13.1 General

This chapter introduces various Boost C++ Libraries defining containers that complement the ones known from the C++
standard. It outlines the usage of containers from Boost.Unordered, added to the C++ standard with Technical Report 1,
shows how to define containers using Boost.MultiIndex and explains when to use Boost.Bimap, a library developed with the
help of Boost.MultiIndex. The first library introduced, however, is Boost.Array which allows to treat traditional arrays just
like containers known from the C++ standard.

13.2 Boost.Array

The library Boost.Array defines a template class boost::array in boost/array.hpp. Using this class, an array can be created
that exhibits the same properties as a traditional array in C++. In addition, boost::array also conforms to the requirements
for C++ containers which makes handling such an array as easy as handling a container. In principle, one can think of
boost::array as the C++ container std::vector with the sole difference of the number of elements in boost::array being
constant.

#include <boost/array.hpp>
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
typedef boost::array<std::string, 3> array;
array a;
a[0] = "Boris";
a.at(1) = "Anton";
*a.rbegin() = "Caesar";
std::sort(a.begin(), a.end());
for (array::const_iterator it = a.begin(); it != a.end(); ++it)
std::cout << *it << std::endl;
std::cout << a.size() << std::endl;
std::cout << a.max_size() << std::endl;
}

Download source code

As seen in the example, the usage of boost::array is fairly simple and needs no additional explanation since the methods
used have the same meaning as their counterparts from std::vector.

One peculiarity is pointed out in the following example though.

#include <boost/array.hpp>
#include <string>
int main()
{
typedef boost::array<std::string, 3> array;
array a = { "Boris", "Anton", "Caesar" };
}

Download source code

An array of type boost::array can be initialized just like a traditional C++ array.

Since this container has been added to the C++ standard with Technical Report 1, it can also be accessed via std::array,
defined in array, if the particular implementation of the C++ standard supports the Technical Report 1 accordingly.

13.3 Boost.Unordered

Boost.Unordered complements the C++ containers std::set, std::multiset, std::map and std::multimap with four additional
classes: boost::unordered_set, boost::unordered_multiset, boost::unordered_map and boost::unordered_multimap. These
classes only differ slightly from the existing containers and even offer a similar interface. In many cases, either one can be
used since the resulting application will only be marginally different.

The difference between the containers of the C++ standard and Boost.Unordered is that containers from Boost.Unordered
do not sort their elements and thus do not require elements to be sortable. Boost.Unordered makes sense whenever the
sortation of stored elements is of no importance.

In order to still find elements quickly, hash values are calculated. Hash values are numbers, uniquely identifying elements
within a container, that can be compared more efficiently than other data types such as strings. Since hash values need to
be calculated, data types stored inside containers of Boost.Unordered must support calculation of these IDs accordingly.
While e.g. std::set requires elements to be sortable, boost::unordered_set requires elements to support hash values.
Despite this requirement, Boost.Unordered is usually preferred unless a sortation of elements is desired.

The following example outlines the usage of boost::unordered_set.

#include <boost/unordered_set.hpp>
#include <iostream>
#include <string>
int main()
{
typedef boost::unordered_set<std::string> unordered_set;
unordered_set set;
set.insert("Boris");
set.insert("Anton");
set.insert("Caesar");
for (unordered_set::iterator it = set.begin(); it != set.end(); ++it)
std::cout << *it << std::endl;
std::cout << set.size() << std::endl;
std::cout << set.max_size() << std::endl;
std::cout << (set.find("David") != set.end()) << std::endl;
std::cout << set.count("Boris") << std::endl;
}

Download source code

As the example shows, boost::unordered_set provides similar methods to std::set. The example could have used std::set
without bigger changes in the source code as well.

The following example uses boost::unordered_map to store the age of each person in addition to the name.

#include <boost/unordered_map.hpp>
#include <iostream>
#include <string>
int main()
{
typedef boost::unordered_map<std::string, int> unordered_map;
unordered_map map;
map.insert(unordered_map::value_type("Boris", 31));
map.insert(unordered_map::value_type("Anton", 35));
map.insert(unordered_map::value_type("Caesar", 25));
for (unordered_map::iterator it = map.begin(); it != map.end(); ++it)
std::cout << it->first << ", " << it->second << std::endl;
std::cout << map.size() << std::endl;
std::cout << map.max_size() << std::endl;
std::cout << (map.find("David") != map.end()) << std::endl;
std::cout << map.count("Boris") << std::endl;
}

Download source code

As with the example before, there are no major differences between boost::unordered_map and std::map. Again, the
example could have been implemented using std::map without any issues.

As mentioned above, Boost.Unordered requires elements stored in the container to support hash values. Miscellaneous data
types such as std::string are supported innately. For user-defined types, a corresponding hash function must be defined
manually.

#include <boost/unordered_set.hpp>
#include <string>
struct person
{
std::string name;
int age;
person(const std::string &n, int a)
: name(n), age(a)
{
}
bool operator==(const person &p) const
{
return name == p.name && age == p.age;
}
};
std::size_t hash_value(person const &p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.name);
boost::hash_combine(seed, p.age);
return seed;
}
int main()
{
typedef boost::unordered_set<person> unordered_set;
unordered_set set;
set.insert(person("Boris", 31));
set.insert(person("Anton", 35));
set.insert(person("Caesar", 25));
}

Download source code

The application stores elements of type person in a container of type boost::unordered_set. Since the built-in hash function
of boost::unordered_set does not recognize the class person, hash values cannot be calculated. Without providing an
alternative hash function, the corresponding code would not compile.

The name of the hash function to be defined is hash_value(). It takes an object of the data type for which a hash value
should be calculated as its sole argument. Since hash values are simple numbers, the return value of the function must be
std::size_t.

Whenever a hash value needs to be calculated for an object, hash_value() is called automatically. The Boost C++ Libraries
already define this function for various data types such as std::string. For user-defined types such as person, it needs to
be defined manually though.

The implementation of hash_value() is usually fairly simple: The hash value is calculated by accessing the individual
properties sequentially using the boost::hash_combine() function from the Boost.Hash library defined in
boost/functional/hash.hpp. This header is automatically included if Boost.Unordered is used since all container calculate
hash values based on Boost.Hash.

Besides implementing the hash_value() function, user-defined types need to support the comparison of two objects via the
== operator. Therefore, person implements the operator==() operator accordingly.

13.4 Boost.MultiIndex

The Boost.MultiIndex library is much more complex than any of the libraries presented thus far. While both Boost.Array and
Boost.Unordered offer containers that can be used immediately, Boost.MultiIndex allows to define new containers. Opposed
to the containers from the C++ standard, a user-defined container offers not only one perception to the data but can
support an arbitrary number of interfaces. For example, one can create a container that assigns values to keys similar to
std::map but also can use the values as keys conversely - something, that without the help of Boost.MultiIndex would
require two containers of type std::map and the overhead of synchronizing the two containers to guarantee data integrity.

The following example defines a new container using Boost.MultiIndex that allows to store the name and age of people.
Contrary to std::map, the container can be searched for both name and age though.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>
struct person
{
std::string name;
int age;
person(const std::string &n, int a)
: name(n), age(a)
{
}
};
typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, std::string, &person::name
>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, int, &person::age
>
>
>
> person_multi;
int main()
{
person_multi persons;
persons.insert(person("Boris", 31));
persons.insert(person("Anton", 35));
persons.insert(person("Caesar", 25));
std::cout << persons.count("Boris") << std::endl;
const person_multi::nth_index<1>::type &age_index = persons.get<1>();
std::cout << age_index.count(25) << std::endl;
}

Download source code

As mentioned before, Boost.MultiIndex does not provide specific containers but rather classes to define new containers.
Typically, the first step is to design the new container by using typedef to access different classes in Boost.MultiIndex.

A class used for every container definition is boost::multi_index::multi_index_container defined in


boost/multi_index_container.hpp. Since it is a template class, at least two arguments are required to be passed
accordingly. The first argument is the data type the container should store; in the above example a user-defined class
named person. The second argument is used to denote different indexes the container should provide.

The key advantage of containers based on Boost.MultiIndex is the ability to access data via different interfaces. The
number and type of interfaces for a specific container can now be specified at definition. Since the container in the example
application allows to search for people either by name or age, two interfaces have been defined. Boost.MultiIndex calls
these interfaces indexes which also influenced the name of the libary.

Interfaces are defined with the help of the boost::multi_index::indexed_by template class. Each interface is passed as an
argument accordingly. The example application defines two interfaces of type boost::multi_index::hashed_non_unique
which is defined in boost/multi_index/hashed_index.hpp. This interface is used if the container should behave just like one
from Boost.Unordered, storing the elements internally using a hash value.

The boost::multi_index::hashed_non_unique class is a template as well and expects a class able to calculate hash values as
its sole argument. Since both interfaces of the container should allow to access people by name and age, one interface
calculates hash values for the name while the other interface does so for the age, respectively.
Boost.MultiIndex offers the helper template class boost::multi_index::member, defined in boost/multi_index/member.hpp,
to access a property. As seen in the above example, several arguments have been specified in order to let
boost::multi_index::member know which property of person should be accessed and which data type the property has.

Even though the definition of person_multi looks quite complicated at first: The class itself operates similar to
boost::unordered_map from Boost.Unordered with the decisive difference of allowing to use both the name and the age of
a person to search the container.

In order to access any MultiIndex container, the interface for the access must be specified - the sole exception being the
first defined interface. If the persons object is directly accessed via insert() or count(), the first interface is implicitly used
- in the case of the example the hash container for the name property. If a different interface should be used, it needs to
be explicitly selected.

Interfaces are numbered consecutively, starting at index 0 for the first interface. In order to access the second interface in
the example, the get() method can be used, passing the index of the desired interface as the template argument.

The return value of get() looks kind of complicated: It accesses a class of the MultiIndex container named nth_index which,
again, is a template and thus the index of the interface to be used must be specified as the template argument
accordingly. This index must be the same as the one passed to the get() method. The final step is to access the type
definition type of nth_index using :: - type actually represents the type of the corresponding interface.

While the specifics of an interface do not need to be known since it is automatically derived from nth_index and type, one
should still understand what kind of interface is accessed. Given that interfaces are numbered consecutively in the
container definition, this can be answered fairly easy given the index that is passed to get() as well as nth_index.
age_index in the example is a hash interface as well - accessing people by age.

Since information such as name and age can be keys of the MultiIndex container based on the interface, they cannot be
changed arbitrarily any longer. If the age of a person is altered after it has been searched for by name, the interface using
the age as the key would not be aware that the key was altered and thus a new hash value needs to be calculated.

Just like the keys in a container of type std::map cannot be modified, information stored within a MultiIndex container
cannot be modified either. Strictly speaking, all information stored in a MultiIndex container is constant. To avoid deleting
and storing altered versions of the information, Boost.MultiIndex offers a couple of useful methods to modify information
directly. Since these methods operate on the MultiIndex container itself and no information is modified directly using the
corresponding object, the update is safe. All interfaces are notified and can e.g. calculate new hash values.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>
struct person
{
std::string name;
int age;
person(const std::string &n, int a)
: name(n), age(a)
{
}
};
typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, std::string, &person::name
>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, int, &person::age
>
>
>
> person_multi;
void set_age(person &p)
{
p.age = 32;
}
int main()
{
person_multi persons;
persons.insert(person("Boris", 31));
persons.insert(person("Anton", 35));
persons.insert(person("Caesar", 25));
person_multi::iterator it = persons.find("Boris");
persons.modify(it, set_age);
const person_multi::nth_index<1>::type &age_index = persons.get<1>();
std::cout << age_index.count(32) << std::endl;
}

Download source code

Every interface offered by Boost.MultiIndex supports the modify() method which operates directly on the container. The
object to be modified is passed using an iterator as the first argument. The second argument is a function or function
object that expects an object of the type stored in the container as its first argument - in the example of type person. This
function - named set_age() - allows to modify an object in the container.

So far, only one interface has been introduced: boost::multi_index::hashed_non_unique calculates a hash value for the
information that does not have to be unparalleled. In order to guarantee that no information is stored twice,
boost::multi_index::hashed_unique can be used instead. Please note that information cannot be stored if it does not satisfy
the requirements of all interfaces of the particular container. If an interface does not allow copies of information, it does
not matter whether a different interfaces does allow them as shown in the following example.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>
struct person
{
std::string name;
int age;
person(const std::string &n, int a)
: name(n), age(a)
{
}
};
typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, std::string, &person::name
>
>,
boost::multi_index::hashed_unique<
boost::multi_index::member<
person, int, &person::age
>
>
>
> person_multi;
int main()
{
person_multi persons;
persons.insert(person("Boris", 31));
persons.insert(person("Anton", 31));
persons.insert(person("Caesar", 25));
const person_multi::nth_index<1>::type &age_index = persons.get<1>();
std::cout << age_index.count(31) << std::endl;
}

Download source code

The container now uses the boost::multi_index::hashed_unique class as the second interface signifying that no two people
can have the same age since otherwise the hash values would be the same.

The application tries to store a person named Anton who is the same age as the already stored person Boris. Since this
violates the requirement of having unique hash values for the second interface, the object is not stored in the container
accordingly. When searching for people of age 31, the application therefore displays 1 ; only the person named Boris has
been stored.

The following example introduces the remaining three interfaces offered by Boost.MultiIndex:
boost::multi_index::sequenced, boost::multi_index::ordered_non_unique and boost::multi_index::random_access.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>
struct person
{
std::string name;
int age;
person(const std::string &n, int a)
: name(n), age(a)
{
}
};
typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>,
boost::multi_index::ordered_non_unique<
boost::multi_index::member<
person, int, &person::age
>
>,
boost::multi_index::random_access<>
>
> person_multi;
int main()
{
person_multi persons;
persons.push_back(person("Boris", 31));
persons.push_back(person("Anton", 31));
persons.push_back(person("Caesar", 25));
const person_multi::nth_index<1>::type &ordered_index = persons.get<1>();
person_multi::nth_index<1>::type::iterator lower = ordered_index.lower_bound(30);
person_multi::nth_index<1>::type::iterator upper = ordered_index.upper_bound(40);
for (; lower != upper; ++lower)
std::cout << lower->name << std::endl;
const person_multi::nth_index<2>::type &random_access_index = persons.get<2>();
std::cout << random_access_index[2].name << std::endl;
}

Download source code

The boost::multi_index::sequenced interface allows to treat a MultiIndex container as a list - similar to std::list. The
interface is fairly simple to use in the definition of the container: No template arguments need to be passed. The objects of
type person are stored exactly in the given order.

By using the boost::multi_index::ordered_non_unique interface, objects are automatically sorted. This interface requires to
specify the sorting criterion while defining the container. The example specifies to sort the objects of type person by age
using the helper class boost::multi_index::member.
boost::multi_index::ordered_non_unique provides special methods to find specific ranges within the sorted information.
Using lower_bound() and upper_bound(), the application searches for people that are older than 30 but no older than 40
years. These methods are not provided with any other interface since they require the information to be sorted.
The final interface is boost::multi_index::random_access, allowing to treat the MultiIndex container just like a vector of
type std::vector. The two prominent methods are operator[]() and at().

Please note that boost::multi_index::random_access completely includes the boost::multi_index::sequenced interface. While
using boost::multi_index::random_access, all methods of boost::multi_index::sequenced are therefore available as well.

After covering the four interfaces of Boost.MultiIndex, the remainder of this section focuses on the so-called key extractors.
One of the key extractors has been introduced so far: boost::multi_index::member defined in
boost/multi_index/member.hpp. This helper class is called key extractor since it allows to explicitly specify which property
of a class should be used as the key of an interface.

The following example introduces two more key extractors.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <iostream>
#include <string>
class person
{
public:
person(const std::string &n, int a)
: name(n), age(a)
{
}
bool operator<(const person &p) const
{
return age < p.age;
}
std::string get_name() const
{
return name;
}
private:
std::string name;
int age;
};
typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::identity<person>
>,
boost::multi_index::hashed_unique<
boost::multi_index::const_mem_fun<
person, std::string, &person::get_name
>
>
>
> person_multi;
int main()
{
person_multi persons;
persons.insert(person("Boris", 31));
persons.insert(person("Anton", 31));
persons.insert(person("Caesar", 25));
std::cout << persons.begin()->get_name() << std::endl;
const person_multi::nth_index<1>::type &hashed_index = persons.get<1>();
std::cout << hashed_index.count("Boris") << std::endl;
}

Download source code

The key extractor boost::multi_index::identity, defined in boost/multi_index/identity.hpp, is used to utilize data types
stored in the container as keys. This requires the person class to be sortable since it is specified as the key for the
interface boost::multi_index::ordered_unique. In the example, this is achieved by providing an overload for the
operator<() operator.

The header file boost/multi_index/mem_fun.hpp defines both the boost::multi_index::const_mem_fun and


boost::multi_index::mem_fun key extractors which can be used to utilize the return value of a method as the key. In the
example application, the return value of get_name() is used accordingly. boost::multi_index::const_mem_fun is used for
constant methods while boost::multi_index::mem_fun is used for non-constant methods.
Boost.MultiIndex offers two more key extractors named boost::multi_index::global_fun and
boost::multi_index::composite_key. While the former can be used for free-standing or static methods, the latter actually
allows to design a key extractor comprising of several other key extractors.

13.5 Boost.Bimap

The Boost.Bimap library is based on Boost.MultiIndex and offers a container that can be used immediately without defining
it first. The container is similar to std::map with the difference of allowing to search for both the key and the value as
shown in the following example.

#include <boost/bimap.hpp>
#include <iostream>
#include <string>
int main()
{
typedef boost::bimap<std::string, int> bimap;
bimap persons;
persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));
std::cout << persons.left.count("Boris") << std::endl;
std::cout << persons.right.count(31) << std::endl;
}

Download source code

boost::bimap is defined in boost/bimap.hpp and offers two properties left and right that can be used to access the two
containers of type std::map unified by boost::bimap. While left accesses the container using keys of type std::string, right
use keys of type int instead.

Besides allowing access to the individual records via a left or right container, boost::bimap allows to view records as
relations as shown in the following example.

#include <boost/bimap.hpp>
#include <iostream>
#include <string>
int main()
{
typedef boost::bimap<std::string, int> bimap;
bimap persons;
persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));
for (bimap::iterator it = persons.begin(); it != persons.end(); ++it)
std::cout << it->left << " is " << it->right << " years old." << std::endl;
}

Download source code

It is not necessary to access records using left or right. By iterating over the records, the left and right container of the
individual record is available through the iterator as well.

While std::map is accompanied by a container named std::multimap that can store multiple records using the same key,
there is no such equivalent for boost::bimap. This, however, does not mean that storing records using the same key inside
a container of type boost::bimap is not possible. Strictly speaking, the two required template arguments do not specify the
data type to store but rather container types used for left and right. If no container type is specified as seen in the
example, the container type boost::bimaps::set_of is used by default which - similar to std::map - only allows records with
unique keys.
The first example for boost::bimap can be rewritten as follows.

#include <boost/bimap.hpp>
#include <iostream>
#include <string>
int main()
{
typedef boost::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::set_of<int>> bimap;
bimap persons;
persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));
std::cout << persons.left.count("Boris") << std::endl;
std::cout << persons.right.count(31) << std::endl;
}

Download source code

Besides boost::bimaps::set_of, other container types exist to customize boost::bimap.

#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <iostream>
#include <string>
int main()
{
typedef boost::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::multiset_of<int>> bimap;
bimap persons;
persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));
std::cout << persons.left.count("Boris") << std::endl;
std::cout << persons.right.count(31) << std::endl;
}

Download source code

The application uses the container type boost::bimaps::multiset_of defined in boost/bimap/multiset_of.hpp. It operates
similar to boost::bimaps::set_of with the exception that the key does not need to be unique. Therefore, the example will
display 2 when searching for people of age 31.
Since boost::bimaps::set_of is used for containers of type boost::bimap by default, the header file boost/bimap/set_of.hpp
does not need to be explicitly included. When using other container types, the corresponding header files must be included
accordingly though.

Boost.Bimap offers the classes boost::bimaps::unordered_set_of, boost::bimaps::unordered_multiset_of,


boost::bimaps::list_of, boost::bimaps::vector_of and boost::bimaps::unconstrainted_set_of in addition to the ones shown
above. Except for boost::bimaps::unconstrainted_set_of, all other container types operate just like their counterparts from
the C++ standard or Boost.Unordered.

#include <boost/bimap.hpp>
#include <boost/bimap/unconstrained_set_of.hpp>
#include <boost/bimap/support/lambda.hpp>
#include <iostream>
#include <string>
int main()
{
typedef boost::bimap<std::string, boost::bimaps::unconstrained_set_of<int>> bimap;
bimap persons;
persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));
bimap::left_map::iterator it = persons.left.find("Boris");
persons.left.modify_key(it, boost::bimaps::_key = "Doris");
std::cout << it->first << std::endl;
}

Download source code

boost::bimaps::unconstrainted_set_of can be used to disable one container type of boost::bimap making it impossible to
access right in order to search for people by age. In this particular case, boost::bimap behaves just like the standard
std::map container.

Nonetheless, the example also shows why it can make sense to prefer boost::bimap over std::map. Since Boost.Bimap is
based on Boost.MultiIndex, methods known from Boost.MultiIndex are available as well. The example modifies a key using
modify_key() which is not possible using std::map.

Please note how the key is modified in detail: A new value is assigned to the current key via boost::bimaps::_key which
is a so-called lambda function as introduced in Chapter3, Function Objects and is defined in
boost/bimap/support/lambda.hpp.

boost/bimap/support/lambda.hpp also defines boost::bimaps::_data. The modify_data() method modifies a value in a


container of type boost::bimap accordingly.

13.6 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Develop an application that assigns employees to departments of a company. Store some example records and
search through them to identify the department of a particular employee as well as the number of employees
working in a particular department.

2. Extend the application by associating numbers to employees. These numbers must be unique in order to identify
employees with the same name unambiguously. Search through the example records to display the information of an
employee with a specific number.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter14:
Chapter 14: Data
Data Structures
Structures
Chapter 15: Error Handling

Chapter 14: Data Structures


Table of Contents 14.1 General
14.2 Boost.Tuple
14.3 Boost.Any
14.4 Boost.Variant
14.5 Exercises

This book is licensed under a Creative Commons License.

14.1 General

For many Boost C++ Libraries, the definition of a container does not apply and thus have not been presented in
Chapter13, Containers. They rather define other data structures introduced in this chapter. For example, boost::tuple
extends the C++ data type std::pair to allow storing not only two but rather an arbitrary number of values.

Besides boost::tuple, this chapter covers the classes boost::any and boost::variant allowing to store values of different
data types. Variables of type boost::any behave just like variables of typeless programming languages which can store any
information. Variables of type boost::variant on the other hand store information of predetermined data types and thus are
similar to a union.

14.2 Boost.Tuple

The Boost.Tuple library provides a class named boost::tuple which can be seen as a generalized version of std::pair. While
std::pair can store exactly two values, boost::tuple gives the user free choice.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string, std::string> person;
person p("Boris", "Schaeling");
std::cout << p << std::endl;
}
Download source code

To use boost::tuple, the header file boost/tuple/tuple.hpp must be included. In order to use tuples with streams, the
header file boost/tuple/tuple_io.hpp is required as well since dependent header files are not automatically included.
boost::tuple is basically used the same way std::pair is. As seen in the above example, two values of type std::string are
stored by specifying two template arguments accordingly.

While the definition of type person could have used std::pair as well, objects of type boost::tuple can be written to a
stream. Again, this requires to include the header file boost/tuple/tuple_io.hpp which provides all the required operators.
The example displays (Boris Schaeling) accordingly.
The important difference between boost::tuple and std::pair is the ability of tuples to store a virtually unlimited number of
values.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p("Boris", "Schaeling", 43);
std::cout << p << std::endl;
}

Download source code

The example now stores the shoe size of people in addition to their first and last name. All three values are placed in a
tuple. When executing the application, it will display (Boris Schaeling 43) .
Just like there exists a helper function std::make_pair() for std::pair, a tuple can be created with the help of the
boost::make_tuple() function.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <iostream>
int main()
{
std::cout << boost::make_tuple("Boris", "Schaeling", 43) << std::endl;
}

Download source code

A tuple can also contain references as shown in the following example.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
std::string s = "Boris";
std::cout << boost::make_tuple(boost::ref(s), "Schaeling", 43) << std::endl;
}

Download source code

While "Schaeling" and 43 are passed by value and thus stored inside the tuple directly, the first element is a reference to
the string s. boost::ref() from Boost.Ref is used to create such a reference. To create a constant reference, boost::cref() is
used, respectively.

After learning how to create tuples, element access is outlined below. std::pair use the properties first and second to
allow access. Since a tuple does not have a fixed number of elements, access is handled in a different way.

#include <boost/tuple/tuple.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p = boost::make_tuple("Boris", "Schaeling", 43);
std::cout << p.get<0>() << std::endl;
std::cout << boost::get<0>(p) << std::endl;
}

Download source code

There exists two ways of accessing values in a tuple: Either by calling the get() member method, or by passing the tuple to
the free-standing boost::get() function. In both cases, the index of the corresponding element in the tuple must be
provided as the template argument. The example accesses the first element of the tuple p in both cases and thus displays
Boris twice.

Specifying an invalid index will result in a compiler error since validity of indexes is checked at compile time to avoid run-
time errors.

To modify a value inside a tuple, either the get() method or the free-standing boost::get() function must be used.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p = boost::make_tuple("Boris", "Schaeling", 43);
p.get<1>() = "Becker";
std::cout << p << std::endl;
}
Download source code

Both get() and boost::get() return a reference. The example modifies the last name and hence displays (Boris Becker 43) .

Boost.Tuple not only offers overloaded operators to use tuples with streams but also defines comparison operators. In
order to compare tuples, the boost/tuple/tuple_comparison.hpp header file must be included accordingly.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p1 = boost::make_tuple("Boris", "Schaeling", 43);
person p2 = boost::make_tuple("Boris", "Becker", 43);
std::cout << (p1 != p2) << std::endl;
}

Download source code

The example displays 1 since the tuples p1 and p2 are different.

The header file boost/tuple/tuple_comparison.hpp also contains definitions for other comparison operators such as greater-
than which performs a lexicographical comparison.

Boost.Tuple supports a specific form of tuples named tier. Tiers are tuples, where all elements are of reference types. They
can be constructed with the boost::tie() function.

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string&, std::string&, int&> person;
std::string firstname = "Boris";
std::string surname = "Schaeling";
int shoesize = 43;
person p = boost::tie(firstname, surname, shoesize);
surname = "Becker";
std::cout << p << std::endl;
}

Download source code

The example creates a tier p which consists of references to the firstname, surname and shoesize variables. By
modifying the variable surname, the tier is modified concurrently.

The above example could have been written using boost::make_tuple() and boost::ref() instead of boost::tie() as well.
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
typedef boost::tuple<std::string&, std::string&, int&> person;
std::string firstname = "Boris";
std::string surname = "Schaeling";
int shoesize = 43;
person p = boost::make_tuple(boost::ref(firstname), boost::ref(surname), boost::ref(shoesize));
surname = "Becker";
std::cout << p << std::endl;
}

Download source code

boost::tie() simply shortens the syntax. This function also lends itself to unpacking tuples. In the following example, the
individual values of the tuple, returned by a function, are instantly stored in variables.

#include <boost/tuple/tuple.hpp>
#include <string>
#include <iostream>
boost::tuple<std::string, int> func()
{
return boost::make_tuple("Error message", 2009);
}
int main()
{
std::string errmsg;
int errcode;
boost::tie(errmsg, errcode) = func();
std::cout << errmsg << ": " << errcode << std::endl;
}

Download source code

Using boost::tie(), the string "Error message" as well as the error code 2009, both returned as a tuple from func(), are
instantly stored in the variables errmsg and errcode.

14.3 Boost.Any

Strongly typed languages such as C++ require that each variable has a specific data type determining the nature of
information it can store. To store arbitrary information in a variable, a language such as JavaScript can be used which
allows storing a character string, a number and a boolean value using the same variable. Variables in JavaScript allow
storing any kind of information.
The library Boost.Any offers the boost::any class which, similar to JavaScript, offers the ability to store arbitrary
information in C++.

#include <boost/any.hpp>
int main()
{
boost::any a = 1;
a = 3.14;
a = true;
}

Download source code

In order to use boost::any, the header file boost/any.hpp must be included. Objects of type boost::any can then be
created to store arbitrary information.

Please note that variables of type boost::any cannot really store any kind of information; Boost.Any requires certain
preconditions, albeit minimal ones. Any information, stored in a variable of type boost::any, must be copy constructible.
Hence, to store a character string in a variable of type boost::any, std::string needs to be explicitly accessed as shown in
the following example.

#include <boost/any.hpp>
#include <string>
int main()
{
boost::any a = 1;
a = 3.14;
a = true;
a = std::string("Hello, world!");
}

Download source code

If the application would try to assign "Hello, world!" to a directly, the compiler would abort with an error since character
strings are arrays comprised of elements of type char which are not copy constructible in C++.

To access the content of variables of type boost::any, the cast operator boost::any_cast must be used.

#include <boost/any.hpp>
#include <iostream>
int main()
{
boost::any a = 1;
std::cout << boost::any_cast<int>(a) << std::endl;
a = 3.14;
std::cout << boost::any_cast<double>(a) << std::endl;
a = true;
std::cout << boost::any_cast<bool>(a) << std::endl;
}
Download source code

By passing the corresponding data type as the template argument to boost::any_cast, the content of the variable is
converted accordingly. In case an invalid data type is specified, an exception of type boost::bad_any_cast is thrown.

#include <boost/any.hpp>
#include <iostream>
int main()
{
try
{
boost::any a = 1;
std::cout << boost::any_cast<float>(a) << std::endl;
}
catch (boost::bad_any_cast &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

The above example throws an exception since the template argument of type float does not match the type int stored in a.
It is important to always specify the same data type as used for the variable of type boost::any. The application would also
throw an exception if either short or long would be specified as the template argument.

Since boost::bad_any_cast is derived from std::bad_cast, catch handlers can catch exceptions of this type accordingly.

To check whether or not a variable of type boost::any contains information, the empty() method is used. To check the data
type of the stored information instead, type() can be used.

#include <boost/any.hpp>
#include <typeinfo>
#include <iostream>
int main()
{
boost::any a = 1;
if (!a.empty())
{
const std::type_info &ti = a.type();
std::cout << ti.name() << std::endl;
}
}

Download source code

The example uses both empty() and type(). While empty() returns a boolean value, the return value of type() is of type
std::type_info which is defined in typeinfo.

To conclude this section, the final example shows how to obtain a pointer to the value stored in a variable of type
boost::any using boost::any_cast.
#include <boost/any.hpp>
#include <iostream>
int main()
{
boost::any a = 1;
int *i = boost::any_cast<int>(&a);
std::cout << *i << std::endl;
}

Download source code

All it takes is passing a pointer to the variable of type boost::any as the argument to boost::any_cast; the template
arguments remain unchanged.

14.4 Boost.Variant

The difference between Boost.Variant and Boost.Any is the ability of Boost.Variant to store a fixed number of types while
Boost.Any allows to store one value of any type. Consider the following example.

#include <boost/variant.hpp>
int main()
{
boost::variant<double, char> v;
v = 3.14;
v = 'A';
}

Download source code

Boost.Variant provides a class named boost::variant which is defined in boost/variant.hpp. Since boost::variant is a
template, at least one argument must be specified. The one or multiple template arguments specify the supported data
types. The example application can store values of both type double and char in v. In case a value of type int would be
assigned to v, the resulting code would not compile.

While the above example could have used a union as well, boost::variant allows to store data types such as std::string
which is not possible with unions since they cannot contain any class member.

#include <boost/variant.hpp>
#include <string>
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
v = 'A';
v = "Hello, world!";
}

Download source code


To display the stored values of v, the free-standing boost::get() function is used.

#include <boost/variant.hpp>
#include <string>
#include <iostream>
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
std::cout << boost::get<double>(v) << std::endl;
v = 'A';
std::cout << boost::get<char>(v) << std::endl;
v = "Hello, world!";
std::cout << boost::get<std::string>(v) << std::endl;
}

Download source code

boost::get() expects one of the valid data types for the corresponding variable as its template argument. Specifying an
invalid type results in a run-time error since validation of data types does not take place during compilation.

Variables of type boost::variant can be written to streams such as the standard output stream directly, bypassing the
hazard of run-time errors.

#include <boost/variant.hpp>
#include <string>
#include <iostream>
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
std::cout << v << std::endl;
v = 'A';
std::cout << v << std::endl;
v = "Hello, world!";
std::cout << v << std::endl;
}

Download source code

To process values differently, Boost.Variant provides a function named boost::apply_visitor().

#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <vector>
#include <string>
#include <iostream>
std::vector<boost::any> vector;
struct output :
public boost::static_visitor<>
{
void operator()(double &d) const
{
vector.push_back(d);
}
void operator()(char &c) const
{
vector.push_back(c);
}
void operator()(std::string &s) const
{
vector.push_back(s);
}
};
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
boost::apply_visitor(output(), v);
v = 'A';
boost::apply_visitor(output(), v);
v = "Hello, world!";
boost::apply_visitor(output(), v);
}

Download source code

As its first argument, boost::apply_visitor() expects an object of a class type derived from boost::static_visitor. This class
must overload the operator()() operator for every data type used in the variable of type boost::variant it acts on.
Consequently, the operator is overloaded three times in the example since v supports the data types double, char and
std::string.

Looking closely at the code, it can be noticed that boost::static_visitor is a template. The type of the return value for the
overloaded operator()() operator must therefore be specified as a template argument. If the operators do not have a return
value, a template argument is not required as seen in the example.

The second argument passed to boost::apply_visitor() is a variable of type boost::variant.

When used, boost::apply_visitor() automatically calls the overloaded operator()() operator of the first argument that
matches the data type passed in the second argument. The example application uses a different overloaded operator every
time boost::apply_visitor() is invoked - first the one for double, followed by the one for char and finally the one for
std::string.

The advantage of boost::apply_visitor() is not only calling the correct operator automatically. In addition,
boost::apply_visitor() ensures that overloaded operators have been provided for every data type supported in variables of
type boost::variant. If the example would have forgotten one of the three methods, the code would have not been
compiled.

If overloaded operators are equal in functionality, the code can be simplified by using templates.
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <vector>
#include <string>
#include <iostream>
std::vector<boost::any> vector;
struct output :
public boost::static_visitor<>
{
template <typename T>
void operator()(T &t) const
{
vector.push_back(t);
}
};
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
boost::apply_visitor(output(), v);
v = 'A';
boost::apply_visitor(output(), v);
v = "Hello, world!";
boost::apply_visitor(output(), v);
}

Download source code

Since boost::apply_visitor() ensures code correctness at compile time, it should be preferred to boost::get().

14.5 Exercises

You can buy solutions to all exercises in this book as a ZIP file.

1. Define a data type configuration that can store name-value pairs. Names are of type std::string while values are of
type std::string, int or float. Inside main(), store the following name-value pairs in an object of type configuration:
path=C:\Windows, version=3 and pi=3.1415. Verify the application by writing the name-value pairs to the standard
output stream.

2. Extend the application by modifying the value of path to C:\Windows\System after displaying it. Verify the
application by writing the name-value pairs to the standard output stream again.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter15:
Chapter 15: Error
Error Handling
Handling
Chapter 16: Cast Operators

Chapter 15: Error Handling


Table of Contents 15.1 General
15.2 Boost.System
15.3 Boost.Exception

This book is licensed under a Creative Commons License.

15.1 General

Every function having the potential to fail during execution needs a way to communicate this to its caller appropriately. In
C++, this is done either by using a return value or by throwing an exception. A return value is usually used if the failure is
not really considered exceptional in a common sense. The caller is expected to check the return value and to react
accordingly.

Exceptions are used to indicate exceptional conditions that are not considered to happen normally. A good example is the
exception of type std::bad_alloc that is thrown if a dynamic memory allocation using new fails. Since memory can usually
be reserved without any issue, it would be cumbersome to always have to check the return value.

This chapter introduces two Boost C++ Libraries assisting a developer in leveraging error handling: Boost.System translates
operating system specific error codes into platform independent ones. Thanks to Boost.System, functions returning a value
based on an operating system type can be designed in a platform-independent way. Boost.Exception allows to add
additional information to any exception that can be utilized inside the catch handler accordingly to better react to the
exception.

15.2 Boost.System

Boost.System is a small library defining four classes to identify errors. boost::system::error_code is the most basic class
and represents operating system specific errors. Since operating systems typically enumerate errors,
boost::system::error_code saves an error code in a variable of type int. The following example illustrates how to use this
class by accessing the Boost.Asio library.

#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <string>
int main()
{
boost::system::error_code ec;
std::string hostname = boost::asio::ip::host_name(ec);
std::cout << ec.value() << std::endl;
}

Download source code

Boost.Asio offers the free-standing boost::asio::ip::host_name() function that returns the name of the computer the
application is executed on.

An object of type boost::system::error_code can be passed as the sole argument to boost::asio::ip::host_name(). If the
underlying operating system function fails, this argument contains the corresponding error code. It is also possible to call
boost::asio::ip::host_name() without any argument in case the error code is irrelevant.

boost::asio::ip::host_name() was actually broken in Boost 1.36.0 and therefore serves as a perfect example. The function
possibly returned an error code even though the underlying operating system function did actually return the name of the
computer successfully. Since the issue was resolved in Boost 1.37.0, boost::asio::ip::host_name() can now be used
without concerns.

Since an error code is nothing but a numeric value, it can be displayed with the help of the value() method. Since the
error code 0 usually means that no error has occurred, the meaning of other values depends on the operating system and
should be looked up in the manual accordingly.

Compiled on Windows XP using Visual Studio 2008, the above application repeatedly generated error code 14 (not enough
storage available to complete the operation) while using Boost 1.36.0. Even though boost::asio::ip::host_name()
successfully determined the name of the computer, error code 14 was reported. This behavior is actually due to a broken
implementation of boost::asio::ip::host_name().

Besides value(), boost::system::error_code offers the category() method. This method returns an object of the second
class defined in Boost.System: boost::system::category.

Error codes are simply numeric values. While operating system manufacturers such as Microsoft are able to guarantee the
uniqueness of system error codes, keeping error codes unique throughout all existing applications is virtually impossible for
any application developer. It would require a centralized database filled with error codes by all software developers to avoid
reusing the same codes for different scenarios which certainly is impractical. For this reason, error categories exist.

Error codes of type boost::system::error_code always belong to a category that can be retrieved using the category()
method. Operating system errors are represented by the predefined object boost::system::system_category.

By calling category(), a reference to the predefined boost::system::system_category is returned. It allows to retrieve


specific information about the category such as the name using the name() method which is system in case of the system
category.

#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <string>
int main()
{
boost::system::error_code ec;
std::string hostname = boost::asio::ip::host_name(ec);
std::cout << ec.value() << std::endl;
std::cout << ec.category().name() << std::endl;
}

Download source code

Errors are uniquely identified by the error code and the error category. Since error codes are only required to be unique
within a category, developers should create a new category whenever they want to define error codes specific to an
application. This allows for arbitrary error codes that do not interfere with error codes of other developers.

#include <boost/system/error_code.hpp>
#include <iostream>
#include <string>
class application_category :
public boost::system::error_category
{
public:
const char *name() const { return "application"; }
std::string message(int ev) const { return "error message"; }
};
application_category cat;
int main()
{
boost::system::error_code ec(14, cat);
std::cout << ec.value() << std::endl;
std::cout << ec.category().name() << std::endl;
}

Download source code

A new error category is defined by creating a class derived from boost::system::error_category and implementing different
methods as required by the interface of the new category. At minimum, the methods name() and message() must be
supplied since they are defined as pure virtual in boost::system::error_category. For additional methods, the default
behavior can be overridden accordingly if required.

While name() returns the name of the error category, message() is used to retrieve the error description for a particular
error code. Unlike the above example, the ev parameter is usually evaluated to return a description based on the error
code.

Objects of type of the newly created error category can be used to initialize an error code accordingly. The example defines
the error code ec using the new application_category category. Therefore, error code 14 is no longer a system error; its
meaning is specified by the developer of the new error category instead.

boost::system::error_code contains a method named default_error_condition() which returns an object of type


boost::system::error_condition. The interface of boost::system::error_condition is almost identical to the one of
boost::system::error_code. The only difference is the default_error_condition() method which is only provided by
boost::system::error_code.

#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <string>
int main()
{
boost::system::error_code ec;
std::string hostname = boost::asio::ip::host_name(ec);
boost::system::error_condition ecnd = ec.default_error_condition();
std::cout << ecnd.value() << std::endl;
std::cout << ecnd.category().name() << std::endl;
}

Download source code

boost::system::error_condition is used just like boost::system::error_code. Both the value() and category() method can be
called for the boost::system::error_condition object as shown in the above example.

The reason for having two more or less identical classes is fairly simple: While boost::system::error_code is used for
platform dependent error codes, boost::system::error_condition is used to access platform independent error codes
instead. By calling the default_error_condition() method, a platform dependent error code is translated into a platform
independent error code of type boost::system::error_condition.

If the above application is executed, it displays the number 12 and the error category GENERIC . The platform dependent
error code 14 has been translated into the platform independent error code 12. Thanks to boost::system::error_condition,
the error is always represented by the same number - disregarding of the underlying platform. While Windows reports the
error as 14, the same error may be reported as 25 with a different operating system. Using
boost::system::error_condition, the error will always be reported as 12.

The last class offered by Boost.System is boost::system::system_error which is derived from std::runtime_error. It can be
used to transport an error code of type boost::system::error_code within an exception.

#include <boost/asio.hpp>
#include <boost/system/system_error.hpp>
#include <iostream>
int main()
{
try
{
std::cout << boost::asio::ip::host_name() << std::endl;
}
catch (boost::system::system_error &e)
{
boost::system::error_code ec = e.code();
std::cerr << ec.value() << std::endl;
std::cerr << ec.category().name() << std::endl;
}
}
Download source code

The free-standing boost::asio::ip::host_name() function is provided in two versions: One expecting an argument of type
boost::system::error_code and one expecting no arguments. The second version will throw an exception of type
boost::system::system_error in case of an error. The exception transports the error code of type
boost::system::error_code accordingly.

15.3 Boost.Exception

The Boost.Exception library offers a new exception type boost::exception allowing to add information to an exception after
it has been thrown. It is defined in boost/exception/exception.hpp. Since Boost.Exception spreads its classes and functions
over multiple header files, the following example rather accesses boost/exception/all.hpp to avoid including the header files
individually.

#include <boost/exception/all.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <exception>
#include <string>
#include <iostream>
typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info;
class allocation_failed :
public boost::exception,
public std::exception
{
public:
allocation_failed(std::size_t size)
: what_("allocation of " + boost::lexical_cast<std::string>(size) + " bytes failed")
{
}
virtual const char *what() const throw()
{
return what_.c_str();
}
private:
std::string what_;
};
boost::shared_array<char> allocate(std::size_t size)
{
if (size > 1000)
throw allocation_failed(size);
return boost::shared_array<char>(new char[size]);
}
void save_configuration_data()
{
try
{
boost::shared_array<char> a = allocate(2000);
// saving configuration data ...
}
catch (boost::exception &e)
{
e << errmsg_info("saving configuration data failed");
throw;
}
}
int main()
{
try
{
save_configuration_data();
}
catch (boost::exception &e)
{
std::cerr << boost::diagnostic_information(e);
}
}

Download source code

The example calls the function save_configuration_data() inside main() which in turn calls the allocate() function. allocate()
allocates memory dynamically; however, it checks whether or not a certain limit is exceeded. This limit is arbitrarily set to
1,000 bytes in the example.

If allocate() is called with a value greater than 1,000, an exception is thrown accordingly which is the case inside the
save_configuration_data() function. The function supposedly saves configuration data in the dynamically allocated memory
as indicated by the comment.

The purpose of the example is to actually throw the exception in order to demonstrate Boost.Exception. The exception,
thrown by allocate(), is of type allocation_failed and is derived from both boost::exception and std::exception.

Deriving from std::exception is certainly not necessary. allocation_failed could have also been derived from a different class
hierarchy in order to embed it inside an existing framework. While the above example uses the class hierarchy defined by
the C++ standard, deriving allocation_failed solely from boost::exception would have also been sufficient.

When throwing an exception of type allocation_failed, the size of the memory expected to be allocated, is stored inside the
exception to alleviate debugging of the corresponding application. If more memory is requested than can be provided by
allocate(), the root cause for the exception can be easily spotted.

If allocate() is called by only one function (in the example save_configuration_data()), this information is sufficient to
locate the issue. However, in more complex applications with many functions calling allocate() to dynamically allocate
memory, the information is no longer sufficient to effectively debug the application. In these cases, it rather would help to
actually know which function tried to allocate more memory than allocate() can provide. Adding more information to the
exception in these cases would help the debugging process tremendously.

The particular challenge is that allocate() does not have information such as the caller name in order to add it to the
exception accordingly.
Boost.Exception offers the following solution: Information can be added to an exception at all times by defining a data type
based on boost::error_info for every information that should be added to the exception.

boost::error_info is a template expecting two arguments: The first argument is a so-called tag, uniquely identifying the
newly created data type. Commonly, a structure with a unique name is utilized. The second argument refers to the data
type of the information stored inside the exception.

The application defined a new data type errmsg_info, uniquely identifiable via the tag_errmsg structure, which stores a
string of type std::string.

Inside the catch handler of save_configuration_data(), the data type tag_errmsg is accessed to create an object, initialized
with the string "saving configuration data failed", to add additional information to the exception of type boost::exception
via the operator<<() operator. The exception is then re-thrown accordingly.

The exception now not only carries the size of memory expected to be dynamically allocated, but also the description of
the error added inside the save_configuration_data() function. This description certainly helps while debugging since it now
becomes clear which function tried to allocate more memory than can be provided.

To retrieve all available information from an exception, the boost::diagnostic_information() function can be used as seen in
the example inside the catch handler of main(). For every exception passed, boost::diagnostic_information() not only calls
the what() method but also accesses all additional information stored inside the exception. A string of type std::string is
returned that can e.g. be written to the standard output stream.

Above application compiled with Visual C++ 2008 displays the following message:

Throw in function (unknown)


Dynamic exception type: class allocation_failed
std::exception::what: allocation of 2000 bytes failed
[struct tag_errmsg *] = saving configuration data failed

As can be seen, the message contains the data type of the exception, the error message as retrieved from the what()
method, and the description including the corresponding name of the structure.

boost::diagnostic_information() checks at run-time whether or not a given exception is derived from std::exception. Only if
it is, the what() method is actually called.

The name of the function that has thrown the exception of type allocation_failed is indicated as "unknown" in the message.

Boost.Exception provides a macro to throw an exception including not only the name of the function but also additional
information such as the file name and the line number.

#include <boost/exception/all.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <exception>
#include <string>
#include <iostream>
typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info;
class allocation_failed :
public std::exception
{
public:
allocation_failed(std::size_t size)
: what_("allocation of " + boost::lexical_cast<std::string>(size) + " bytes failed")
{
}
virtual const char *what() const throw()
{
return what_.c_str();
}
private:
std::string what_;
};
boost::shared_array<char> allocate(std::size_t size)
{
if (size > 1000)
BOOST_THROW_EXCEPTION(allocation_failed(size));
return boost::shared_array<char>(new char[size]);
}
void save_configuration_data()
{
try
{
boost::shared_array<char> a = allocate(2000);
// saving configuration data ...
}
catch (boost::exception &e)
{
e << errmsg_info("saving configuration data failed");
throw;
}
}
int main()
{
try
{
save_configuration_data();
}
catch (boost::exception &e)
{
std::cerr << boost::diagnostic_information(e);
}
}

Download source code

By using the macro BOOST_THROW_EXCEPTION instead of throw, additional information such as function name, file name
and line number are automatically added to the exception. This only works if the compiler supports corresponding macros
though. While macros such as __FILE__ and __LINE__ are defined by the C++ standard, there is no standardized macro
for returning the name of the current function. Since many of the compiler manufacturers provide such a macro,
BOOST_THROW_EXCEPTION tries to identify the underlying compiler and utilize the corresponding macro accordingly.
Compiled with Visual C++ 2008, the above application displays the following message:

.\main.cpp(31): Throw in function class boost::shared_array<char> __cdecl allocate(unsigned int)


Dynamic exception type: class boost::exception_detail::clone_impl<struct
boost::exception_detail::error_info_injector<class allocation_failed> >
std::exception::what: allocation of 2000 bytes failed
[struct tag_errmsg *] = saving configuration data failed

The code compiles without errors even though the allocation_failed class is no longer derived from boost::exception.
BOOST_THROW_EXCEPTION accesses a function named boost::enable_error_info() that dynamically identifies whether or
not an exception is derived from boost::exception. If not, it automatically creates a new exception type derived both from
the specified type and boost::exception. This mechanism is the reason for the above message to not display
allocation_failed only.

Finally, this section concludes with an example to selectively access information added to an exception.

#include <boost/exception/all.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <exception>
#include <string>
#include <iostream>
typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info;
class allocation_failed :
public std::exception
{
public:
allocation_failed(std::size_t size)
: what_("allocation of " + boost::lexical_cast<std::string>(size) + " bytes failed")
{
}
virtual const char *what() const throw()
{
return what_.c_str();
}
private:
std::string what_;
};
boost::shared_array<char> allocate(std::size_t size)
{
if (size > 1000)
BOOST_THROW_EXCEPTION(allocation_failed(size));
return boost::shared_array<char>(new char[size]);
}
void save_configuration_data()
{
try
{
boost::shared_array<char> a = allocate(2000);
// saving configuration data ...
}
catch (boost::exception &e)
{
e << errmsg_info("saving configuration data failed");
throw;
}
}
int main()
{
try
{
save_configuration_data();
}
catch (boost::exception &e)
{
std::cerr << *boost::get_error_info<errmsg_info>(e);
}
}

Download source code

The example does not utilize boost::diagnostic_information() but rather uses boost::get_error_info() to directly access the
error message of type errmsg_info. boost::get_error_info() returns a smart pointer of type boost::shared_ptr. In case the
argument passed is not of type boost::exception, a null pointer is returned accordingly. If the BOOST_THROW_EXCEPTION
macro is always used to throw an exception, it is guaranteed that the exception is derived from boost::exception - there is
no need to check the returned smart pointer for null in these cases.

Copyright 2008-2010 Boris Schling


The Boost C++ Libraries Chapter16:
Chapter 16: Cast
Cast Operators
Operators

Chapter 16: Cast Operators


Table of Contents 16.1 General
16.2 Boost.Conversion
16.3 Boost.NumericConversion

This book is licensed under a Creative Commons License.

16.1 General

The C++ standard defines four cast operators: static_cast, dynamic_cast, const_cast and reinterpret_cast. The two libraries
Boost.Conversion and Boost.NumericConversion define additional cast operators specialized for certain type casts.

16.2 Boost.Conversion

The library Boost.Conversion consists of only two header files. While boost/cast.hpp defines the two cast operators
boost::polymorphic_cast and boost::polymorphic_downcast, boost/lexical_cast.hpp offers the cast operator
boost::lexical_cast, respectively.

The goal of boost::polymorphic_cast and boost::polymorphic_downcast is to embody type casts, usually done with
dynamic_cast, more precisely as shown in the following example.

struct father
{
virtual ~father() { };
};
struct mother
{
virtual ~mother() { };
};
struct child :
public father,
public mother
{
};
void func(father *f)
{
child *c = dynamic_cast<child*>(f);
}
int main()
{
child *c = new child;
func(c);
father *f = new child;
mother *m = dynamic_cast<mother*>(f);
}

Download source code

The example uses the cast operator dynamic_cast twice: It transforms the pointer pointing to a parent class to one
pointing to the child class in func(). In main(), it transforms the pointer pointing to a parent class to one pointing to a
different parent class. The first transformation is called downcast while the second one is called cross cast, respectively.

By using the cast operators of Boost.Conversion, a downcast can be distinguished from a cross cast.

#include <boost/cast.hpp>
struct father
{
virtual ~father() { };
};
struct mother
{
virtual ~mother() { };
};
struct child :
public father,
public mother
{
};
void func(father *f)
{
child *c = boost::polymorphic_downcast<child*>(f);
}
int main()
{
child *c = new child;
func(c);
father *f = new child;
mother *m = boost::polymorphic_cast<mother*>(f);
}

Download source code

The cast operator boost::polymorphic_downcast can only be used for downcasts. It uses static_cast internally to perform
the cast. Since static_cast does not dynamically check whether or not the type cast is valid, boost::polymorphic_downcast
should only be used if the type cast is safe. In debug builds, boost::polymorphic_downcast actually uses dynamic_cast to
verify the validity of the type cast using the assert() function. Please note that this test is only performed as long as the
NDEBUG macro is defined which is usually the case for debug builds.

While downcasts are possible using boost::polymorphic_downcast, boost::polymorphic_cast is required for cross casts.
boost::polymorphic_cast internally uses dynamic_cast since it is the only cast operator able to perform a cross cast. It still
makes sense to prefer boost::polymorphic_cast since it will throw an exception of type std::bad_cast in case of an error.
dynamic_cast, on the contrary, will return 0 if the type cast fails. Instead of manually verifying the return value,
boost::polymorphic_cast provides an automatic way instead.

Both boost::polymorphic_downcast and boost::polymorphic_cast can only be used if pointers must be converted; otherwise,
dynamic_cast must be used. Since boost::polymorphic_downcast is based on static_cast, it is not able to e.g. convert
objects of a parent class to objects of a child class. It also does not make much sense to use boost::polymorphic_cast if
types other than pointers should be converted as dynamic_cast throws an exception of type std::bad_cast in this case as
well.

While the usage of boost::polymorphic_downcast and boost::polymorphic_cast is not really mandatory since all type casts
can also be performed using dynamic_cast, Boost.Conversion also offers a second cast operator fairly beneficial in practice.
Consider the following example.

#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>
int main()
{
std::string s = boost::lexical_cast<std::string>(169);
std::cout << s << std::endl;
double d = boost::lexical_cast<double>(s);
std::cout << d << std::endl;
}

Download source code

The cast operator boost::lexical_cast can convert numbers of different data types. The example first converts the integer
169 to a string before converting the string to a floating-point number in a second step.

boost::lexical_cast internally uses streams to perform the conversion. Therefore, only types with overloaded operator<<()
and operator>>() operators can be converted. The advantage of using boost::lexical_cast is that type conversions occur
within one line of code without the need for manipulating the streams manually. Since the usage of streams for type
conversions may not immediately become apparent, cast operators such as boost::lexical_cast also help to make the code
more meaningful.

Please note that boost::lexical_cast not necessarily accesses streams; it can be optimized for different data types as well.
If a conversion fails, an exception of type boost::bad_lexical_cast, derived from std::bad_cast, is thrown.

#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>
int main()
{
try
{
int i = boost::lexical_cast<int>("abc");
std::cout << i << std::endl;
}
catch (boost::bad_lexical_cast &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

The example throws an exception since the string "abc" cannot be converted to a number of type int.

16.3 Boost.NumericConversion

The library Boost.NumericConversion can be used to convert numbers of one type to numbers of a different type. In C++,
such a conversion can also take place implicitly as shown in the following example.

#include <iostream>
int main()
{
int i = 0x10000;
short s = i;
std::cout << s << std::endl;
}

Download source code

The example is compiled without any error since the type conversion from int to short takes place automatically. Even
though the application can be executed, the result of the conversion cannot be predicted but rather depends on the actual
compiler and its implementation. The number 0x10000 in the variable i is too big to be stored in a variable of type short.
Per the C++ standard, the result of this operation is "implementation defined". Compiled with Visual C++ 2008, the
application displays 0 . The value of s certainly differs from the value in i.
To avoid these kind of errors while converting numbers, the cast operator boost::numeric_cast can be used.

#include <boost/numeric/conversion/cast.hpp>
#include <iostream>
int main()
{
try
{
int i = 0x10000;
short s = boost::numeric_cast<short>(i);
std::cout << s << std::endl;
}
catch (boost::numeric::bad_numeric_cast &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

boost::numeric_cast is used exactly like the known C++ cast operators. The correct header file must certainly be included
though; in this case boost/numeric/conversion/cast.hpp.

boost::numeric_cast executes the same conversion than C++ does implicitly. However, boost::numeric_cast actually
verifies whether or not the conversion can take place without changing the value of the number to be converted. Given the
example application, a conversion would not take place. Instead, an exception of type boost::numeric::bad_numeric_cast is
thrown since 0x10000 is too big to be placed in a variable of type short.

Strictly speaking, an exception of type boost::numeric::positive_overflow is thrown. This type specifies a so-called overflow
- in this case for positive numbers. There also exists a type boost::numeric::negative_overflow which specifies an overflow
for negative numbers instead.

#include <boost/numeric/conversion/cast.hpp>
#include <iostream>
int main()
{
try
{
int i = -0x10000;
short s = boost::numeric_cast<short>(i);
std::cout << s << std::endl;
}
catch (boost::numeric::negative_overflow &e)
{
std::cerr << e.what() << std::endl;
}
}

Download source code

Boost.NumericConversion defines additional exception types, all derived from boost::numeric::bad_numeric_cast. Since
boost::numeric::bad_numeric_cast is derived from std::bad_cast itself, a catch handler can also catch exceptions of this
type.

Copyright 2008-2010 Boris Schling


#include <windows.h>

class windows_handle
{
public:
windows_handle(HANDLE h)
: handle_(h)
{
}

~windows_handle()
{
CloseHandle(handle_);
}

HANDLE handle() const


{
return handle_;
}

private:
HANDLE handle_;
};

int main()
{
windows_handle h(OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetCurrentProcessId()));
SetPriorityClass(h.handle(), HIGH_PRIORITY_CLASS);
}
#include <boost/scoped_ptr.hpp>

int main()
{
boost::scoped_ptr<int> i(new int);
*i = 1;
*i.get() = 2;
i.reset(new int);
}
#include <boost/scoped_array.hpp>

int main()
{
boost::scoped_array<int> i(new int[2]);
*i.get() = 1;
i[1] = 2;
i.reset(new int[3]);
}
#include <boost/shared_ptr.hpp>
#include <vector>

int main()
{
std::vector<boost::shared_ptr<int> > v;
v.push_back(boost::shared_ptr<int>(new int(1)));
v.push_back(boost::shared_ptr<int>(new int(2)));
}
#include <boost/shared_ptr.hpp>

int main()
{
boost::shared_ptr<int> i1(new int(1));
boost::shared_ptr<int> i2(i1);
i1.reset(new int(2));
}
#include <boost/shared_ptr.hpp>
#include <windows.h>

int main()
{
boost::shared_ptr<void> h(OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetCurrentProcessId()), CloseHandle);
SetPriorityClass(h.get(), HIGH_PRIORITY_CLASS);
}
#include <boost/shared_array.hpp>
#include <iostream>

int main()
{
boost::shared_array<int> i1(new int[2]);
boost::shared_array<int> i2(i1);
i1[0] = 1;
std::cout << i2[0] << std::endl;
}
#include <windows.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <iostream>

DWORD WINAPI reset(LPVOID p)


{
boost::shared_ptr<int> *sh = static_cast<boost::shared_ptr<int>*>(p);
sh->reset();
return 0;
}

DWORD WINAPI print(LPVOID p)


{
boost::weak_ptr<int> *w = static_cast<boost::weak_ptr<int>*>(p);
boost::shared_ptr<int> sh = w->lock();
if (sh)
std::cout << *sh << std::endl;
return 0;
}

int main()
{
boost::shared_ptr<int> sh(new int(99));
boost::weak_ptr<int> w(sh);
HANDLE threads[2];
threads[0] = CreateThread(0, 0, reset, &sh, 0, 0);
threads[1] = CreateThread(0, 0, print, &w, 0, 0);
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
}
#include <boost/intrusive_ptr.hpp>
#include <atlbase.h>
#include <iostream>

void intrusive_ptr_add_ref(IDispatch *p)


{
p->AddRef();
}

void intrusive_ptr_release(IDispatch *p)


{
p->Release();
}

void check_windows_folder()
{
CLSID clsid;
CLSIDFromProgID(CComBSTR("Scripting.FileSystemObject"), &clsid);
void *p;
CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, __uuidof(IDispatch), &p);
boost::intrusive_ptr<IDispatch> disp(static_cast<IDispatch*>(p));
CComDispatchDriver dd(disp.get());
CComVariant arg("C:\\Windows");
CComVariant ret(false);
dd.Invoke1(CComBSTR("FolderExists"), &arg, &ret);
std::cout << (ret.boolVal != 0) << std::endl;
}

void main()
{
CoInitialize(0);
check_windows_folder();
CoUninitialize();
}
#include <boost/shared_ptr.hpp>
#include <vector>

int main()
{
std::vector<boost::shared_ptr<int> > v;
v.push_back(boost::shared_ptr<int>(new int(1)));
v.push_back(boost::shared_ptr<int>(new int(2)));
}
#include <boost/ptr_container/ptr_vector.hpp>

int main()
{
boost::ptr_vector<int> v;
v.push_back(new int(1));
v.push_back(new int(2));
}
#include <iostream>
#include <cstring>

char *get(const char *s)


{
int size = std::strlen(s);
char *text = new char[size + 1];
std::strncpy(text, s, size + 1);
return text;
}

void print(char *text)


{
std::cout << text << std::endl;
}

int main(int argc, char *argv[])


{
if (argc < 2)
{
std::cerr << argv[0] << " <data>" << std::endl;
return 1;
}

char *text = get(argv[1]);


print(text);
delete[] text;
}
#include <vector>

template <typename T>


T *create()
{
return new T;
}

int main()
{
std::vector<int*> v;
v.push_back(create<int>());
}
#include <iostream>
#include <vector>
#include <algorithm>

void print(int i)
{
std::cout << i << std::endl;
}

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::for_each(v.begin(), v.end(), print);


}
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

class add
: public std::binary_function<int, int, void>
{
public:
void operator()(int i, int j) const
{
std::cout << i + j << std::endl;
}
};

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::for_each(v.begin(), v.end(), std::bind1st(add(), 10));


}
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>

void add(int i, int j)


{
std::cout << i + j << std::endl;
}

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1));


}
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>

bool compare(int i, int j)


{
return i > j;
}

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2));


}
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>

bool compare(int i, int j)


{
return i > j;
}

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::sort(v.begin(), v.end(), compare);


}
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>

bool compare(int i, int j)


{
return i > j;
}

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1));


}
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>

void add(int i, int j, std::ostream &os)


{
os << i + j << std::endl;
}

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1, boost::ref(std::cout)));


}
#include <boost/function.hpp>
#include <iostream>
#include <cstdlib>
#include <cstring>

int main()
{
boost::function<int (const char*)> f = std::atoi;
std::cout << f("1609") << std::endl;
f = std::strlen;
std::cout << f("1609") << std::endl;
}
#include <boost/function.hpp>
#include <iostream>

int main()
{
try
{
boost::function<int (const char*)> f;
f("");
}
catch (boost::bad_function_call &ex)
{
std::cout << ex.what() << std::endl;
}
}
#include <boost/function.hpp>
#include <iostream>

struct world
{
void hello(std::ostream &os)
{
os << "Hello, world!" << std::endl;
}
};

int main()
{
boost::function<void (world*, std::ostream&)> f = &world::hello;
world w;
f(&w, boost::ref(std::cout));
}
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::for_each(v.begin(), v.end(), std::cout << boost::lambda::_1 << "\n");


}
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/if.hpp>
#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(2);

std::for_each(v.begin(), v.end(),
boost::lambda::if_then(boost::lambda::_1 > 1,
std::cout << boost::lambda::_1 << "\n"));
}
#include <algorithm>
#include <functional>
#include <vector>
#include <iostream>

class divide_by
: public std::binary_function<int, int, int>
{
public:
int operator()(int n, int div) const
{
return n / div;
}
};

int main()
{
std::vector<int> numbers;
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);

std::transform(numbers.begin(), numbers.end(), numbers.begin(), std::bind2nd(divide_by(), 2));

for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)


std::cout << *it << std::endl;
}
#include <string>
#include <vector>
#include <iostream>

int main()
{
std::vector<std::string> strings;
strings.push_back("Boost");
strings.push_back("C++");
strings.push_back("Libraries");

std::vector<int> sizes;

for (std::vector<std::string>::iterator it = strings.begin(); it != strings.end(); ++it)


sizes.push_back(it->size());

for (std::vector<int>::iterator it = sizes.begin(); it != sizes.end(); ++it)


std::cout << *it << std::endl;
}
#include <vector>
#include <iostream>
#include <cstdlib>
#include <cstring>

int main()
{
std::vector<int(*)(const char*)> processors;
processors.push_back(std::atoi);
processors.push_back(reinterpret_cast<int(*)(const char*)>(std::strlen));

const char data[] = "1.23";

for (std::vector<int(*)(const char*)>::iterator it = processors.begin(); it != processors.end(); ++it)


std::cout << (*it)(data) << std::endl;
}
#include <boost/signal.hpp>
#include <iostream>

void func()
{
std::cout << "Hello, world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
s.connect(func);
s();
}
#include <boost/function.hpp>
#include <iostream>

void func()
{
std::cout << "Hello, world!" << std::endl;
}

int main()
{
boost::function<void ()> f;
f = func;
f();
}
#include <boost/signal.hpp>
#include <iostream>

void func1()
{
std::cout << "Hello" << std::flush;
}

void func2()
{
std::cout << ", world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
s.connect(func1);
s.connect(func2);
s();
}
#include <boost/signal.hpp>
#include <iostream>

void func1()
{
std::cout << "Hello" << std::flush;
}

void func2()
{
std::cout << ", world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
s.connect(1, func2);
s.connect(0, func1);
s();
}
#include <boost/signal.hpp>
#include <iostream>

void func1()
{
std::cout << "Hello" << std::endl;
}

void func2()
{
std::cout << ", world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
s.connect(func1);
s.connect(func2);
s.disconnect(func2);
s();
}
#include <boost/signal.hpp>
#include <iostream>

void func1()
{
std::cout << "Hello" << std::flush;
}

void func2()
{
std::cout << ", world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
s.connect(func1);
s.connect(func2);
std::cout << s.num_slots() << std::endl;
if (!s.empty())
s();
s.disconnect_all_slots();
}
#include <boost/signal.hpp>
#include <iostream>

int func1()
{
return 1;
}

int func2()
{
return 2;
}

int main()
{
boost::signal<int ()> s;
s.connect(func1);
s.connect(func2);
std::cout << s() << std::endl;
}
#include <boost/signal.hpp>
#include <iostream>
#include <algorithm>

int func1()
{
return 1;
}

int func2()
{
return 2;
}

template <typename T>


struct min_element
{
typedef T result_type;

template <typename InputIterator>


T operator()(InputIterator first, InputIterator last) const
{
return *std::min_element(first, last);
}
};

int main()
{
boost::signal<int (), min_element<int> > s;
s.connect(func1);
s.connect(func2);
std::cout << s() << std::endl;
}
#include <boost/signal.hpp>
#include <iostream>
#include <vector>
#include <algorithm>

int func1()
{
return 1;
}

int func2()
{
return 2;
}

template <typename T>


struct min_element
{
typedef T result_type;

template <typename InputIterator>


T operator()(InputIterator first, InputIterator last) const
{
return T(first, last);
}
};

int main()
{
boost::signal<int (), min_element<std::vector<int> > > s;
s.connect(func1);
s.connect(func2);
std::vector<int> v = s();
std::cout << *std::min_element(v.begin(), v.end()) << std::endl;
}
#include <boost/signal.hpp>
#include <iostream>

void func()
{
std::cout << "Hello, world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
boost::signals::connection c = s.connect(func);
s();
c.disconnect();
}
#include <boost/signal.hpp>
#include <iostream>

void func()
{
std::cout << "Hello, world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
boost::signals::connection c = s.connect(func);
c.block();
s();
c.unblock();
s();
}
#include <boost/signal.hpp>
#include <iostream>

void func()
{
std::cout << "Hello, world!" << std::endl;
}

int main()
{
boost::signal<void ()> s;
{
boost::signals::scoped_connection c = s.connect(func);
}
s();
}
#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <memory>

class world
{
public:
void hello() const
{
std::cout << "Hello, world!" << std::endl;
}
};

int main()
{
boost::signal<void ()> s;
{
std::auto_ptr<world> w(new world());
s.connect(boost::bind(&world::hello, w.get()));
}
std::cout << s.num_slots() << std::endl;
s();
}
#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <memory>

class world :
public boost::signals::trackable
{
public:
void hello() const
{
std::cout << "Hello, world!" << std::endl;
}
};

int main()
{
boost::signal<void ()> s;
{
std::auto_ptr<world> w(new world());
s.connect(boost::bind(&world::hello, w.get()));
}
std::cout << s.num_slots() << std::endl;
s();
}
#include <locale>
#include <iostream>

int main()
{
std::locale loc;
std::cout << loc.name() << std::endl;
}
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::locale loc;
std::cout << loc.name() << std::endl;
}
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German_Switzerland"));
std::locale loc;
std::cout << loc.name() << std::endl;
}
#include <locale>
#include <iostream>
#include <cstring>

int main()
{
std::cout << std::strcoll("", "z") << std::endl;
std::locale::global(std::locale("German"));
std::cout << std::strcoll("", "z") << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
#include <clocale>

int main()
{
std::setlocale(LC_ALL, "German");
std::string s = "Boris Schling";
std::cout << boost::algorithm::to_upper_copy(s) << std::endl;
std::cout << boost::algorithm::to_upper_copy(s, std::locale("German")) << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::to_upper_copy(s) << std::endl;
std::cout << boost::algorithm::to_upper_copy(s, std::locale("German")) << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::erase_first_copy(s, "i") << std::endl;
std::cout << boost::algorithm::erase_nth_copy(s, "i", 0) << std::endl;
std::cout << boost::algorithm::erase_last_copy(s, "i") << std::endl;
std::cout << boost::algorithm::erase_all_copy(s, "i") << std::endl;
std::cout << boost::algorithm::erase_head_copy(s, 5) << std::endl;
std::cout << boost::algorithm::erase_tail_copy(s, 8) << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::iterator_range<std::string::iterator> r = boost::algorithm::find_first(s, "Boris");
std::cout << r << std::endl;
r = boost::algorithm::find_first(s, "xyz");
std::cout << r << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
#include <vector>

int main()
{
std::locale::global(std::locale("German"));
std::vector<std::string> v;
v.push_back("Boris");
v.push_back("Schling");
std::cout << boost::algorithm::join(v, " ") << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::replace_first_copy(s, "B", "D") << std::endl;
std::cout << boost::algorithm::replace_nth_copy(s, "B", 0, "D") << std::endl;
std::cout << boost::algorithm::replace_last_copy(s, "B", "D") << std::endl;
std::cout << boost::algorithm::replace_all_copy(s, "B", "D") << std::endl;
std::cout << boost::algorithm::replace_head_copy(s, 5, "Doris") << std::endl;
std::cout << boost::algorithm::replace_tail_copy(s, 8, "Becker") << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "\t Boris Schling \t";
std::cout << "." << boost::algorithm::trim_left_copy(s) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_right_copy(s) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_copy(s) << "." << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "--Boris Schling--";
std::cout << "." << boost::algorithm::trim_left_copy_if(s, boost::algorithm::is_any_of("-")) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_right_copy_if(s, boost::algorithm::is_any_of("-")) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_copy_if(s, boost::algorithm::is_any_of("-")) << "." << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "123456789Boris Schling123456789";
std::cout << "." << boost::algorithm::trim_left_copy_if(s, boost::algorithm::is_digit()) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_right_copy_if(s, boost::algorithm::is_digit()) << "." << std::endl;
std::cout << "." <<boost::algorithm::trim_copy_if(s, boost::algorithm::is_digit()) << "." << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::cout << boost::algorithm::starts_with(s, "Boris") << std::endl;
std::cout << boost::algorithm::ends_with(s, "Schling") << std::endl;
std::cout << boost::algorithm::contains(s, "is") << std::endl;
std::cout << boost::algorithm::lexicographical_compare(s, "Boris") << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <locale>
#include <iostream>
#include <vector>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
std::vector<std::string> v;
boost::algorithm::split(v, s, boost::algorithm::is_space());
std::cout << v.size() << std::endl;
}
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::iterator_range<std::string::iterator> r = boost::algorithm::find_regex(s, boost::regex("\\w\\s\\w"));
std::cout << r << std::endl;
}
#include <boost/regex.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("\\w+\\s\\w+");
std::cout << boost::regex_match(s, expr) << std::endl;
}
#include <boost/regex.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("(\\w+)\\s(\\w+)");
boost::smatch what;
if (boost::regex_search(s, what, expr))
{
std::cout << what[0] << std::endl;
std::cout << what[1] << " " << what[2] << std::endl;
}
}
#include <boost/regex.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = " Boris Schling ";
boost::regex expr("\\s");
std::string fmt("_");
std::cout << boost::regex_replace(s, expr, fmt) << std::endl;
}
#include <boost/regex.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("(\\w+)\\s(\\w+)");
std::string fmt("\\2 \\1");
std::cout << boost::regex_replace(s, expr, fmt) << std::endl;
}
#include <boost/regex.hpp>
#include <locale>
#include <iostream>

int main()
{
std::locale::global(std::locale("German"));
std::string s = "Boris Schling";
boost::regex expr("(\\w+)\\s(\\w+)");
std::string fmt("\\2 \\1");
std::cout << boost::regex_replace(s, expr, fmt, boost::regex_constants::format_literal) << std::endl;
}
#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
tokenizer tok(s);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}
#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
boost::char_separator<char> sep(" ");
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}
#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
boost::char_separator<char> sep(" ", "+");
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}
#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
std::string s = "Boost C++ libraries";
boost::char_separator<char> sep(" ", "+", boost::keep_empty_tokens);
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}
#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tokenizer<boost::char_separator<wchar_t>, std::wstring::const_iterator, std::wstring> tokenizer;
std::wstring s = L"Boost C++ libraries";
boost::char_separator<wchar_t> sep(L" ");
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::wcout << *it << std::endl;
}
#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tokenizer<boost::escaped_list_separator<char> > tokenizer;
std::string s = "Boost,\"C++ libraries\"";
tokenizer tok(s);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}
#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tokenizer<boost::offset_separator> tokenizer;
std::string s = "Boost C++ libraries";
int offsets[] = { 5, 5, 9 };
boost::offset_separator sep(offsets, offsets + 3);
tokenizer tok(s, sep);
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
std::cout << *it << std::endl;
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
std::cout << boost::format("%1%.%2%.%3%") % 16 % 9 % 2008 << std::endl;
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
std::cout << boost::format("%2%/%1%/%3%") % 16 % 9 % 2008 << std::endl;
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
std::cout << boost::format("%1% %2% %1%") % boost::io::group(std::showpos, 99) % 100 << std::endl;
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
std::cout << boost::format("%|1$+| %2% %1%") % 99 % 100 << std::endl;
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
try
{
std::cout << boost::format("%|+| %2% %1%") % 99 % 100 << std::endl;
}
catch (boost::io::format_error &ex)
{
std::cout << ex.what() << std::endl;
}
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
std::cout << boost::format("%|+| %|| %||") % 99 % 100 % 99 << std::endl;
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
std::cout << boost::format("%+d %d %d") % 99 % 100 % 99 << std::endl;
}
#include <boost/format.hpp>
#include <iostream>

int main()
{
std::cout << boost::format("%+s %s %s") % 99 % 100 % 99 << std::endl;
}
#include <boost/thread.hpp>
#include <iostream>

void wait(int seconds)


{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << std::endl;
}
}

int main()
{
boost::thread t(thread);
t.join();
}
#include <boost/thread.hpp>
#include <iostream>

void wait(int seconds)


{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

void thread()
{
try
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << std::endl;
}
}
catch (boost::thread_interrupted&)
{
}
}

int main()
{
boost::thread t(thread);
wait(3);
t.interrupt();
t.join();
}
#include <boost/thread.hpp>
#include <iostream>

int main()
{
std::cout << boost::this_thread::get_id() << std::endl;
std::cout << boost::thread::hardware_concurrency() << std::endl;
}
#include <boost/thread.hpp>
#include <iostream>

void wait(int seconds)


{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

boost::mutex mutex;

void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
mutex.lock();
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
mutex.unlock();
}
}

int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}
#include <boost/thread.hpp>
#include <iostream>

void wait(int seconds)


{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

boost::mutex mutex;

void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
}
}

int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}
#include <boost/thread.hpp>
#include <iostream>

void wait(int seconds)


{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

boost::timed_mutex mutex;

void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
boost::unique_lock<boost::timed_mutex> lock(mutex, boost::try_to_lock);
if (!lock.owns_lock())
lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(1));
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
boost::timed_mutex *m = lock.release();
m->unlock();
}
}

int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}
#include <boost/thread.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

void wait(int seconds)


{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

boost::shared_mutex mutex;
std::vector<int> random_numbers;

void fill()
{
std::srand(static_cast<unsigned int>(std::time(0)));
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::shared_mutex> lock(mutex);
random_numbers.push_back(std::rand());
lock.unlock();
wait(1);
}
}

void print()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
boost::shared_lock<boost::shared_mutex> lock(mutex);
std::cout << random_numbers.back() << std::endl;
}
}

int sum = 0;

void count()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
boost::shared_lock<boost::shared_mutex> lock(mutex);
sum += random_numbers.back();
}
}

int main()
{
boost::thread t1(fill);
boost::thread t2(print);
boost::thread t3(count);
t1.join();
t2.join();
t3.join();
std::cout << "Summe: " << sum << std::endl;
}
#include <boost/thread.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

boost::mutex mutex;
boost::condition_variable_any cond;
std::vector<int> random_numbers;

void fill()
{
std::srand(static_cast<unsigned int>(std::time(0)));
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::mutex> lock(mutex);
random_numbers.push_back(std::rand());
cond.notify_all();
cond.wait(mutex);
}
}

void print()
{
std::size_t next_size = 1;
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::mutex> lock(mutex);
while (random_numbers.size() != next_size)
cond.wait(mutex);
std::cout << random_numbers.back() << std::endl;
++next_size;
cond.notify_all();
}
}

int main()
{
boost::thread t1(fill);
boost::thread t2(print);
t1.join();
t2.join();
}
#include <boost/thread.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>

void init_number_generator()
{
static bool done = false;
if (!done)
{
done = true;
std::srand(static_cast<unsigned int>(std::time(0)));
}
}

boost::mutex mutex;

void random_number_generator()
{
init_number_generator();
int i = std::rand();
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << i << std::endl;
}

int main()
{
boost::thread t[3];

for (int i = 0; i < 3; ++i)


t[i] = boost::thread(random_number_generator);

for (int i = 0; i < 3; ++i)


t[i].join();
}
#include <boost/thread.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>

void init_number_generator()
{
static boost::thread_specific_ptr<bool> tls;
if (!tls.get())
tls.reset(new bool(false));
if (!*tls)
{
*tls = true;
std::srand(static_cast<unsigned int>(std::time(0)));
}
}

boost::mutex mutex;

void random_number_generator()
{
init_number_generator();
int i = std::rand();
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << i << std::endl;
}

int main()
{
boost::thread t[3];

for (int i = 0; i < 3; ++i)


t[i] = boost::thread(random_number_generator);

for (int i = 0; i < 3; ++i)


t[i].join();
}
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/cstdint.hpp>
#include <iostream>

int main()
{
boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();

boost::uint64_t sum = 0;
for (int i = 0; i < 1000000000; ++i)
sum += i;

boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time();


std::cout << end - start << std::endl;

std::cout << sum << std::endl;


}
#include <iostream>

int sum = 0;

void calculate()
{
for (int i = 0; i < 1000; ++i)
sum += i;
}

void print()
{
std::cout << sum << std::endl;
}

void thread()
{
calculate();
print();
}

int main()
{
thread();
}
#include <boost/asio.hpp>
#include <iostream>

void handler(const boost::system::error_code &ec)


{
std::cout << "5 s." << std::endl;
}

int main()
{
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(5));
timer.async_wait(handler);
io_service.run();
}
#include <boost/asio.hpp>
#include <iostream>

void handler1(const boost::system::error_code &ec)


{
std::cout << "5 s." << std::endl;
}

void handler2(const boost::system::error_code &ec)


{
std::cout << "10 s." << std::endl;
}

int main()
{
boost::asio::io_service io_service;
boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(10));
timer2.async_wait(handler2);
io_service.run();
}
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>

void handler1(const boost::system::error_code &ec)


{
std::cout << "5 s." << std::endl;
}

void handler2(const boost::system::error_code &ec)


{
std::cout << "5 s." << std::endl;
}

boost::asio::io_service io_service;

void run()
{
io_service.run();
}

int main()
{
boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(5));
timer2.async_wait(handler2);
boost::thread thread1(run);
boost::thread thread2(run);
thread1.join();
thread2.join();
}
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>

void handler1(const boost::system::error_code &ec)


{
std::cout << "5 s." << std::endl;
}

void handler2(const boost::system::error_code &ec)


{
std::cout << "5 s." << std::endl;
}

boost::asio::io_service io_service1;
boost::asio::io_service io_service2;

void run1()
{
io_service1.run();
}

void run2()
{
io_service2.run();
}

int main()
{
boost::asio::deadline_timer timer1(io_service1, boost::posix_time::seconds(5));
timer1.async_wait(handler1);
boost::asio::deadline_timer timer2(io_service2, boost::posix_time::seconds(5));
timer2.async_wait(handler2);
boost::thread thread1(run1);
boost::thread thread2(run2);
thread1.join();
thread2.join();
}
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <string>

boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::socket sock(io_service);
boost::array<char, 4096> buffer;

void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)


{
if (!ec)
{
std::cout << std::string(buffer.data(), bytes_transferred) << std::endl;
sock.async_read_some(boost::asio::buffer(buffer), read_handler);
}
}

void connect_handler(const boost::system::error_code &ec)


{
if (!ec)
{
boost::asio::write(sock, boost::asio::buffer("GET / HTTP 1.1\r\nHost: highscore.de\r\n\r\n"));
sock.async_read_some(boost::asio::buffer(buffer), read_handler);
}
}

void resolve_handler(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator it)


{
if (!ec)
{
sock.async_connect(*it, connect_handler);
}
}

int main()
{
boost::asio::ip::tcp::resolver::query query("www.highscore.de", "80");
resolver.async_resolve(query, resolve_handler);
io_service.run();
}
#include <boost/asio.hpp>
#include <string>

boost::asio::io_service io_service;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 80);
boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint);
boost::asio::ip::tcp::socket sock(io_service);
std::string data = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";

void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)


{
}

void accept_handler(const boost::system::error_code &ec)


{
if (!ec)
{
boost::asio::async_write(sock, boost::asio::buffer(data), write_handler);
}
}

int main()
{
acceptor.listen();
acceptor.async_accept(sock, accept_handler);
io_service.run();
}
#include <boost/asio.hpp>
#include <cstddef>

template <typename Service>


class basic_timer
: public boost::asio::basic_io_object<Service>
{
public:
explicit basic_timer(boost::asio::io_service &io_service)
: boost::asio::basic_io_object<Service>(io_service)
{
}

void wait(std::size_t seconds)


{
return this->service.wait(this->implementation, seconds);
}

template <typename Handler>


void async_wait(std::size_t seconds, Handler handler)
{
this->service.async_wait(this->implementation, seconds, handler);
}
};
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/system/error_code.hpp>

template <typename TimerImplementation = timer_impl>


class basic_timer_service
: public boost::asio::io_service::service
{
public:
static boost::asio::io_service::id id;

explicit basic_timer_service(boost::asio::io_service &io_service)


: boost::asio::io_service::service(io_service),
async_work_(new boost::asio::io_service::work(async_io_service_)),
async_thread_(boost::bind(&boost::asio::io_service::run, &async_io_service_))
{
}

~basic_timer_service()
{
async_work_.reset();
async_io_service_.stop();
async_thread_.join();
}

typedef boost::shared_ptr<TimerImplementation> implementation_type;

void construct(implementation_type &impl)


{
impl.reset(new TimerImplementation());
}

void destroy(implementation_type &impl)


{
impl->destroy();
impl.reset();
}

void wait(implementation_type &impl, std::size_t seconds)


{
boost::system::error_code ec;
impl->wait(seconds, ec);
boost::asio::detail::throw_error(ec);
}

template <typename Handler>


class wait_operation
{
public:
wait_operation(implementation_type &impl, boost::asio::io_service &io_service, std::size_t seconds, Handler handler)
: impl_(impl),
io_service_(io_service),
work_(io_service),
seconds_(seconds),
handler_(handler)
{
}

void operator()() const


{
implementation_type impl = impl_.lock();
if (impl)
{
boost::system::error_code ec;
impl->wait(seconds_, ec);
this->io_service_.post(boost::asio::detail::bind_handler(handler_, ec));
}
else
{
this->io_service_.post(boost::asio::detail::bind_handler(handler_, boost::asio::error::operation_aborted));
}
}

private:
boost::weak_ptr<TimerImplementation> impl_;
boost::asio::io_service &io_service_;
boost::asio::io_service::work work_;
std::size_t seconds_;
Handler handler_;
};

template <typename Handler>


void async_wait(implementation_type &impl, std::size_t seconds, Handler handler)
{
this->async_io_service_.post(wait_operation<Handler>(impl, this->get_io_service(), seconds, handler));
}

private:
void shutdown_service()
{
}

boost::asio::io_service async_io_service_;
boost::scoped_ptr<boost::asio::io_service::work> async_work_;
boost::thread async_thread_;
};

template <typename TimerImplementation>


boost::asio::io_service::id basic_timer_service<TimerImplementation>::id;
#include <boost/system/error_code.hpp>
#include <cstddef>
#include <windows.h>

class timer_impl
{
public:
timer_impl()
: handle_(CreateEvent(NULL, FALSE, FALSE, NULL))
{
}

~timer_impl()
{
CloseHandle(handle_);
}

void destroy()
{
SetEvent(handle_);
}

void wait(std::size_t seconds, boost::system::error_code &ec)


{
DWORD res = WaitForSingleObject(handle_, seconds * 1000);
if (res == WAIT_OBJECT_0)
ec = boost::asio::error::operation_aborted;
else
ec = boost::system::error_code();
}

private:
HANDLE handle_;
};
#include <boost/asio.hpp>
#include <iostream>
#include "basic_timer.hpp"
#include "timer_impl.hpp"
#include "basic_timer_service.hpp"

void wait_handler(const boost::system::error_code &ec)


{
std::cout << "5 s." << std::endl;
}

typedef basic_timer<basic_timer_service<> > timer;

int main()
{
boost::asio::io_service io_service;
timer t(io_service);
t.async_wait(5, wait_handler);
io_service.run();
}
#include <boost/interprocess/shared_memory_object.hpp>
#include <iostream>

int main()
{
boost::interprocess::shared_memory_object shdmem(boost::interprocess::open_or_create, "Highscore", boost::interprocess::read_write);
shdmem.truncate(1024);
std::cout << shdmem.get_name() << std::endl;
boost::interprocess::offset_t size;
if (shdmem.get_size(size))
std::cout << size << std::endl;
}
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>

int main()
{
boost::interprocess::shared_memory_object shdmem(boost::interprocess::open_or_create, "Highscore", boost::interprocess::read_write);
shdmem.truncate(1024);
boost::interprocess::mapped_region region(shdmem, boost::interprocess::read_write);
std::cout << std::hex << "0x" << region.get_address() << std::endl;
std::cout << std::dec << region.get_size() << std::endl;
boost::interprocess::mapped_region region2(shdmem, boost::interprocess::read_only);
std::cout << std::hex << "0x" << region2.get_address() << std::endl;
std::cout << std::dec << region2.get_size() << std::endl;
}
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>

int main()
{
boost::interprocess::shared_memory_object shdmem(boost::interprocess::open_or_create, "Highscore", boost::interprocess::read_write);
shdmem.truncate(1024);
boost::interprocess::mapped_region region(shdmem, boost::interprocess::read_write);
int *i1 = static_cast<int*>(region.get_address());
*i1 = 99;
boost::interprocess::mapped_region region2(shdmem, boost::interprocess::read_only);
int *i2 = static_cast<int*>(region2.get_address());
std::cout << *i2 << std::endl;
}
#include <boost/interprocess/shared_memory_object.hpp>
#include <iostream>

int main()
{
bool removed = boost::interprocess::shared_memory_object::remove("Highscore");
std::cout << removed << std::endl;
}
#include <boost/interprocess/windows_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>

int main()
{
boost::interprocess::windows_shared_memory shdmem(boost::interprocess::open_or_create, "Highscore", boost::interprocess::read_write, 1024);
boost::interprocess::mapped_region region(shdmem, boost::interprocess::read_write);
int *i1 = static_cast<int*>(region.get_address());
*i1 = 99;
boost::interprocess::mapped_region region2(shdmem, boost::interprocess::read_only);
int *i2 = static_cast<int*>(region2.get_address());
std::cout << *i2 << std::endl;
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>

int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "Highscore", 1024);
int *i = managed_shm.construct<int>("Integer")(99);
std::cout << *i << std::endl;
std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer");
if (p.first)
std::cout << *p.first << std::endl;
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>

int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "Highscore", 1024);
int *i = managed_shm.construct<int>("Integer")[10](99);
std::cout << *i << std::endl;
std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer");
if (p.first)
{
std::cout << *p.first << std::endl;
std::cout << p.second << std::endl;
}
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>

int main()
{
try
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "Highscore", 1024);
int *i = managed_shm.construct<int>("Integer")[4096](99);
}
catch (boost::interprocess::bad_alloc &ex)
{
std::cerr << ex.what() << std::endl;
}
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>

int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "Highscore", 1024);
int *i = managed_shm.find_or_construct<int>("Integer")(99);
std::cout << *i << std::endl;
managed_shm.destroy<int>("Integer");
std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer");
std::cout << p.first << std::endl;
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <iostream>

int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "Highscore", 1024);
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> string;
string *s = managed_shm.find_or_construct<string>("String")("Hello!", managed_shm.get_segment_manager());
s->insert(5, ", world");
std::cout << *s << std::endl;
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/bind.hpp>
#include <iostream>

void construct_objects(boost::interprocess::managed_shared_memory &managed_shm)


{
managed_shm.construct<int>("Integer")(99);
managed_shm.construct<float>("Float")(3.14);
}

int main()
{
boost::interprocess::shared_memory_object::remove("Highscore");
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "Highscore", 1024);
managed_shm.atomic_func(boost::bind(construct_objects, boost::ref(managed_shm)));
std::cout << *managed_shm.find<int>("Integer").first << std::endl;
std::cout << *managed_shm.find<float>("Float").first << std::endl;
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <iostream>

int main()
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm", 1024);
int *i = managed_shm.find_or_construct<int>("Integer")();
boost::interprocess::named_mutex named_mtx(boost::interprocess::open_or_create, "mtx");
named_mtx.lock();
++(*i);
std::cout << *i << std::endl;
named_mtx.unlock();
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <iostream>

int main()
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm", 1024);
int *i = managed_shm.find_or_construct<int>("Integer")();
boost::interprocess::interprocess_mutex *mtx = managed_shm.find_or_construct<boost::interprocess::interprocess_mutex>("mtx")();
mtx->lock();
++(*i);
std::cout << *i << std::endl;
mtx->unlock();
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>

int main()
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm", 1024);
int *i = managed_shm.find_or_construct<int>("Integer")(0);
boost::interprocess::named_mutex named_mtx(boost::interprocess::open_or_create, "mtx");
boost::interprocess::named_condition named_cnd(boost::interprocess::open_or_create, "cnd");
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(named_mtx);
while (*i < 10)
{
if (*i % 2 == 0)
{
++(*i);
named_cnd.notify_all();
named_cnd.wait(lock);
}
else
{
std::cout << *i << std::endl;
++(*i);
named_cnd.notify_all();
named_cnd.wait(lock);
}
}
named_cnd.notify_all();
boost::interprocess::shared_memory_object::remove("shm");
boost::interprocess::named_mutex::remove("mtx");
boost::interprocess::named_condition::remove("cnd");
}
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>

int main()
{
try
{
boost::interprocess::managed_shared_memory managed_shm(boost::interprocess::open_or_create, "shm", 1024);
int *i = managed_shm.find_or_construct<int>("Integer")(0);
boost::interprocess::interprocess_mutex *mtx = managed_shm.find_or_construct<boost::interprocess::interprocess_mutex>("mtx")();
boost::interprocess::interprocess_condition *cnd = managed_shm.find_or_construct<boost::interprocess::interprocess_condition>("cnd")();
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(*mtx);
while (*i < 10)
{
if (*i % 2 == 0)
{
++(*i);
cnd->notify_all();
cnd->wait(lock);
}
else
{
std::cout << *i << std::endl;
++(*i);
cnd->notify_all();
cnd->wait(lock);
}
}
cnd->notify_all();
}
catch (...)
{
}
boost::interprocess::shared_memory_object::remove("shm");
}
#include <boost/filesystem.hpp>

int main()
{
boost::filesystem::path p1("C:\\");
boost::filesystem::path p2("C:\\Windows");
boost::filesystem::path p3("C:\\Program Files");
}
#include <boost/filesystem.hpp>

int main()
{
boost::filesystem::path p1("...");
boost::filesystem::path p2("\\");
boost::filesystem::path p3("@:");
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\Windows\\System");
std::cout << p.string() << std::endl;
std::cout << p.file_string() << std::endl;
std::cout << p.directory_string() << std::endl;
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("/");
std::cout << p.string() << std::endl;
std::cout << p.file_string() << std::endl;
std::cout << p.directory_string() << std::endl;
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\Windows\\System");
std::cout << p.root_name() << std::endl;
std::cout << p.root_directory() << std::endl;
std::cout << p.root_path() << std::endl;
std::cout << p.relative_path() << std::endl;
std::cout << p.parent_path() << std::endl;
std::cout << p.filename() << std::endl;
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("photo.jpg");
std::cout << p.stem() << std::endl;
std::cout << p.extension() << std::endl;
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\Windows\\System");
for (boost::filesystem::path::iterator it = p.begin(); it != p.end(); ++it)
std::cout << *it << std::endl;
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\");
p /= "Windows\\System";
std::cout << p.string() << std::endl;
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\");
try
{
boost::filesystem::file_status s = boost::filesystem::status(p);
std::cout << boost::filesystem::is_directory(s) << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\Windows\\win.ini");
try
{
std::cout << boost::filesystem::file_size(p) << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/filesystem.hpp>
#include <iostream>
#include <ctime>

int main()
{
boost::filesystem::path p("C:\\Windows\\win.ini");
try
{
std::time_t t = boost::filesystem::last_write_time(p);
std::cout << std::ctime(&t) << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\");
try
{
boost::filesystem::space_info s = boost::filesystem::space(p);
std::cout << s.capacity << std::endl;
std::cout << s.free << std::endl;
std::cout << s.available << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("C:\\Test");
try
{
if (boost::filesystem::create_directory(p))
{
boost::filesystem::rename(p, "C:\\Test2");
boost::filesystem::remove("C:\\Test2");
}
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
try
{
std::cout << boost::filesystem::complete("photo.jpg") << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
try
{
std::cout << boost::filesystem::complete("photo.jpg", "D:\\") << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <windows.h>
#include <boost/filesystem.hpp>
#include <iostream>

int main()
{
try
{
std::cout << boost::filesystem::current_path() << std::endl;
SetCurrentDirectory("C:\\");
std::cout << boost::filesystem::current_path() << std::endl;
}
catch (boost::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/filesystem/fstream.hpp>
#include <iostream>

int main()
{
boost::filesystem::path p("test.txt");
boost::filesystem::ofstream ofs(p);
ofs << "Hello, world!" << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d(2010, 1, 30);
std::cout << d.year() << std::endl;
std::cout << d.month() << std::endl;
std::cout << d.day() << std::endl;
std::cout << d.day_of_week() << std::endl;
std::cout << d.end_of_month() << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d = boost::gregorian::day_clock::universal_day();
std::cout << d.year() << std::endl;
std::cout << d.month() << std::endl;
std::cout << d.day() << std::endl;

d = boost::gregorian::date_from_iso_string("20100131");
std::cout << d.year() << std::endl;
std::cout << d.month() << std::endl;
std::cout << d.day() << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d1(2008, 1, 31);
boost::gregorian::date d2(2008, 8, 31);
boost::gregorian::date_duration dd = d2 - d1;
std::cout << dd.days() << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date_duration dd(4);
std::cout << dd.days() << std::endl;
boost::gregorian::weeks ws(4);
std::cout << ws.days() << std::endl;
boost::gregorian::months ms(4);
std::cout << ms.number_of_months() << std::endl;
boost::gregorian::years ys(4);
std::cout << ys.number_of_years() << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d(2009, 1, 31);
boost::gregorian::months ms(1);
boost::gregorian::date d2 = d + ms;
std::cout << d2 << std::endl;
boost::gregorian::date d3 = d2 - ms;
std::cout << d3 << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d(2009, 1, 30);
boost::gregorian::months ms(1);
boost::gregorian::date d2 = d + ms;
std::cout << d2 << std::endl;
boost::gregorian::date d3 = d2 - ms;
std::cout << d3 << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d1(2009, 1, 30);
boost::gregorian::date d2(2009, 10, 31);
boost::gregorian::date_period dp(d1, d2);
boost::gregorian::date_duration dd = dp.length();
std::cout << dd.days() << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d1(2009, 1, 30);
boost::gregorian::date d2(2009, 10, 31);
boost::gregorian::date_period dp(d1, d2);
std::cout << dp.contains(d1) << std::endl;
std::cout << dp.contains(d2) << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::gregorian::date d(2009, 1, 5);
boost::gregorian::day_iterator it(d);
std::cout << *++it << std::endl;
std::cout << boost::date_time::next_weekday(*it, boost::gregorian::greg_weekday(boost::date_time::Friday)) << std::endl;
}
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12, 0, 0));
boost::gregorian::date d = pt.date();
std::cout << d << std::endl;
boost::posix_time::time_duration td = pt.time_of_day();
std::cout << td << std::endl;
}
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

int main()
{
boost::posix_time::ptime pt = boost::posix_time::second_clock::universal_time();
std::cout << pt.date() << std::endl;
std::cout << pt.time_of_day() << std::endl;

pt = boost::posix_time::from_iso_string("20090105T120000");
std::cout << pt.date() << std::endl;
std::cout << pt.time_of_day() << std::endl;
}
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main()
{
boost::posix_time::time_duration td(16, 30, 0);
std::cout << td.hours() << std::endl;
std::cout << td.minutes() << std::endl;
std::cout << td.seconds() << std::endl;
std::cout << td.total_seconds() << std::endl;
}
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main()
{
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12, 0, 0));
boost::posix_time::ptime pt2(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(18, 30, 0));
boost::posix_time::time_duration td = pt2 - pt1;
std::cout << td.hours() << std::endl;
std::cout << td.minutes() << std::endl;
std::cout << td.seconds() << std::endl;
}
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main()
{
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12, 0, 0));
boost::posix_time::time_duration td(6, 30, 0);
boost::posix_time::ptime pt2 = pt1 + td;
std::cout << pt2.time_of_day() << std::endl;
}
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main()
{
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12, 0, 0));
boost::posix_time::ptime pt2(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(18, 30, 0));
boost::posix_time::time_period tp(pt1, pt2);
std::cout << tp.contains(pt1) << std::endl;
std::cout << tp.contains(pt2) << std::endl;
}
#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>

int main()
{
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 05), boost::posix_time::time_duration(12, 0, 0));
boost::posix_time::time_iterator it(pt, boost::posix_time::time_duration(6, 30, 0));
std::cout << *++it << std::endl;
std::cout << *++it << std::endl;
}
#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>

int main()
{
boost::local_time::time_zone_ptr tz(new boost::local_time::posix_time_zone("CET+1"));
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12, 0, 0));
boost::local_time::local_date_time dt(pt, tz);
std::cout << dt.utc_time() << std::endl;
std::cout << dt << std::endl;
std::cout << dt.local_time() << std::endl;
std::cout << dt.zone_name() << std::endl;
}
#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>

int main()
{
boost::local_time::time_zone_ptr tz(new boost::local_time::posix_time_zone("CET+1"));
boost::posix_time::ptime pt(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12, 0, 0));
boost::local_time::local_date_time dt(pt, tz);
std::cout << dt.local_time() << std::endl;
boost::local_time::time_zone_ptr tz2(new boost::local_time::posix_time_zone("EET+2"));
std::cout << dt.local_time_in(tz2).local_time() << std::endl;
}
#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>

int main()
{
boost::local_time::time_zone_ptr tz(new boost::local_time::posix_time_zone("CET+0"));
boost::posix_time::ptime pt1(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(12, 0, 0));
boost::local_time::local_date_time dt1(pt1, tz);
boost::posix_time::ptime pt2(boost::gregorian::date(2009, 1, 5), boost::posix_time::time_duration(18, 0, 0));
boost::local_time::local_date_time dt2(pt2, tz);
boost::local_time::local_time_period tp(dt1, dt2);
std::cout << tp.contains(dt1) << std::endl;
std::cout << tp.contains(dt2) << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <locale>

int main()
{
boost::gregorian::date d(2009, 1, 7);
boost::gregorian::date_facet *df = new boost::gregorian::date_facet("%A, %d %B %Y");
std::cout.imbue(std::locale(std::cout.getloc(), df));
std::cout << d << std::endl;
}
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <locale>
#include <string>
#include <vector>

int main()
{
std::locale::global(std::locale("German"));
std::string months[12] = { "Januar", "Februar", "Mrz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" };
std::string weekdays[7] = { "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag" };
boost::gregorian::date d(2009, 1, 7);
boost::gregorian::date_facet *df = new boost::gregorian::date_facet("%A, %d. %B %Y");
df->long_month_names(std::vector<std::string>(months, months + 12));
df->long_weekday_names(std::vector<std::string>(weekdays, weekdays + 7));
std::cout.imbue(std::locale(std::cout.getloc(), df));
std::cout << d << std::endl;
}
#include <boost/archive/text_oarchive.hpp>
#include <iostream>

int main()
{
boost::archive::text_oarchive oa(std::cout);
int i = 1;
oa << i;
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <fstream>

void save()
{
std::ofstream file("archiv.txt");
boost::archive::text_oarchive oa(file);
int i = 1;
oa << i;
}

void load()
{
std::ifstream file("archiv.txt");
boost::archive::text_iarchive ia(file);
int i = 0;
ia >> i;
std::cout << i << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

void save()
{
boost::archive::text_oarchive oa(ss);
int i = 1;
oa << i;
}

void load()
{
boost::archive::text_iarchive ia(ss);
int i = 0;
ia >> i;
std::cout << i << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}

int age_;
};

void save()
{
boost::archive::text_oarchive oa(ss);
person p(31);
oa << p;
}

void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


friend void serialize(Archive &ar, person &p, const unsigned int version);

int age_;
};

template <typename Archive>


void serialize(Archive &ar, person &p, const unsigned int version)
{
ar & p.age_;
}
void save()
{
boost::archive::text_oarchive oa(ss);
person p(31);
oa << p;
}

void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <iostream>
#include <sstream>
#include <string>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age, const std::string &name)


: age_(age), name_(name)
{
}

int age() const


{
return age_;
}

std::string name() const


{
return name_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


friend void serialize(Archive &ar, person &p, const unsigned int version);

int age_;
std::string name_;
};

template <typename Archive>


void serialize(Archive &ar, person &p, const unsigned int version)
{
ar & p.age_;
ar & p.name_;
}

void save()
{
boost::archive::text_oarchive oa(ss);
person p(31, "Boris");
oa << p;
}

void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
std::cout << p.name() << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <iostream>
#include <sstream>
#include <string>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age, const std::string &name)


: age_(age), name_(name)
{
}

int age() const


{
return age_;
}

std::string name() const


{
return name_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


friend void serialize(Archive &ar, person &p, const unsigned int version);

int age_;
std::string name_;
};

template <typename Archive>


void serialize(Archive &ar, person &p, const unsigned int version)
{
ar & p.age_;
if (version > 0)
ar & p.name_;
}

BOOST_CLASS_VERSION(person, 1)

void save()
{
boost::archive::text_oarchive oa(ss);
person p(31, "Boris");
oa << p;
}

void load()
{
boost::archive::text_iarchive ia(ss);
person p;
ia >> p;
std::cout << p.age() << std::endl;
std::cout << p.name() << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}

int age_;
};

void save()
{
boost::archive::text_oarchive oa(ss);
person *p = new person(31);
oa << p;
std::cout << std::hex << p << std::endl;
delete p;
}

void load()
{
boost::archive::text_iarchive ia(ss);
person *p;
ia >> p;
std::cout << std::hex << p << std::endl;
std::cout << p->age() << std::endl;
delete p;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/scoped_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}

int age_;
};

void save()
{
boost::archive::text_oarchive oa(ss);
boost::scoped_ptr<person> p(new person(31));
oa << p;
}

void load()
{
boost::archive::text_iarchive ia(ss);
boost::scoped_ptr<person> p;
ia >> p;
std::cout << p->age() << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}

int age_;
};

void save()
{
boost::archive::text_oarchive oa(ss);
person p(31);
person &pp = p;
oa << pp;
}

void load()
{
boost::archive::text_iarchive ia(ss);
person p;
person &pp = p;
ia >> pp;
std::cout << pp.age() << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <iostream>
#include <sstream>
#include <string>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}

int age_;
};

class developer
: public person
{
public:
developer()
{
}

developer(int age, const std::string &language)


: person(age), language_(language)
{
}

std::string language() const


{
return language_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<person>(*this);
ar & language_;
}

std::string language_;
};

void save()
{
boost::archive::text_oarchive oa(ss);
developer d(31, "C++");
oa << d;
}

void load()
{
boost::archive::text_iarchive ia(ss);
developer d;
ia >> d;
std::cout << d.age() << std::endl;
std::cout << d.language() << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
#include <sstream>
#include <string>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

virtual int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}

int age_;
};
class developer
: public person
{
public:
developer()
{
}

developer(int age, const std::string &language)


: person(age), language_(language)
{
}

std::string language() const


{
return language_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<person>(*this);
ar & language_;
}

std::string language_;
};

BOOST_CLASS_EXPORT(developer)

void save()
{
boost::archive::text_oarchive oa(ss);
person *p = new developer(31, "C++");
oa << p;
delete p;
}

void load()
{
boost::archive::text_iarchive ia(ss);
person *p;
ia >> p;
std::cout << p->age() << std::endl;
delete p;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
#include <sstream>
#include <string>

std::stringstream ss;

class person
{
public:
person()
{
}

person(int age)
: age_(age)
{
}

virtual int age() const


{
return age_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & age_;
}

int age_;
};
class developer
: public person
{
public:
developer()
{
}

developer(int age, const std::string &language)


: person(age), language_(language)
{
}

std::string language() const


{
return language_;
}

private:
friend class boost::serialization::access;

template <typename Archive>


void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<person>(*this);
ar & language_;
}

std::string language_;
};

void save()
{
boost::archive::text_oarchive oa(ss);
oa.register_type<developer>();
person *p = new developer(31, "C++");
oa << p;
delete p;
}
void load()
{
boost::archive::text_iarchive ia(ss);
ia.register_type<developer>();
person *p;
ia >> p;
std::cout << p->age() << std::endl;
delete p;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

void save()
{
boost::archive::text_oarchive oa(ss);
boost::array<int, 3> a = { 0, 1, 2 };
oa << a;
}

void load()
{
boost::archive::text_iarchive ia(ss);
boost::array<int, 3> a;
ia >> a;
std::cout << a[0] << ", " << a[1] << ", " << a[2] << std::endl;
}

int main()
{
save();
load();
}
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/array.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <sstream>

std::stringstream ss;

void save()
{
boost::archive::text_oarchive oa(ss);
boost::array<int, 3> a = { 0, 1, 2 };
oa << boost::serialization::make_array(a.data(), a.size());
}

void load()
{
boost::archive::text_iarchive ia(ss);
boost::array<int, 3> a;
ia >> boost::serialization::make_array(a.data(), a.size());
std::cout << a[0] << ", " << a[1] << ", " << a[2] << std::endl;
}

int main()
{
save();
load();
}
#include <boost/spirit.hpp>

struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
template <typename Scanner>
struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;

definition(const json_grammar &self)


{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | "true" | "false" | "null";
number = real_p;
array = "[" >> value >> *("," >> value) >> "]";
}

const boost::spirit::rule<Scanner> &start()


{
return object;
}
};
};

int main()
{
}
#include <boost/spirit.hpp>
#include <fstream>
#include <sstream>
#include <iostream>

struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
template <typename Scanner>
struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;

definition(const json_grammar &self)


{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | "true" | "false" | "null";
number = real_p;
array = "[" >> value >> *("," >> value) >> "]";
}

const boost::spirit::rule<Scanner> &start()


{
return object;
}
};
};

int main(int argc, char *argv[])


{
std::ifstream fs(argv[1]);
std::ostringstream ss;
ss << fs.rdbuf();
std::string data = ss.str();

json_grammar g;
boost::spirit::parse_info<> pi = boost::spirit::parse(data.c_str(), g, boost::spirit::space_p);
if (pi.hit)
{
if (pi.full)
std::cout << "parsing all data successfully" << std::endl;
else
std::cout << "parsing data partially" << std::endl;
std::cout << pi.length << " characters parsed" << std::endl;
}
else
std::cout << "parsing failed; stopped at '" << pi.stop << "'" << std::endl;
}
#include <boost/spirit.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
struct print
{
void operator()(const char *begin, const char *end) const
{
std::cout << std::string(begin, end) << std::endl;
}
};

template <typename Scanner>


struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;

definition(const json_grammar &self)


{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string[print()] >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | "true" | "false" | "null";
number = real_p;
array = "[" >> value >> *("," >> value) >> "]";
}

const boost::spirit::rule<Scanner> &start()


{
return object;
}
};
};
int main(int argc, char *argv[])
{
std::ifstream fs(argv[1]);
std::ostringstream ss;
ss << fs.rdbuf();
std::string data = ss.str();

json_grammar g;
boost::spirit::parse_info<> pi = boost::spirit::parse(data.c_str(), g, boost::spirit::space_p);
if (pi.hit)
{
if (pi.full)
std::cout << "parsing all data successfully" << std::endl;
else
std::cout << "parsing data partially" << std::endl;
std::cout << pi.length << " characters parsed" << std::endl;
}
else
std::cout << "parsing failed; stopped at '" << pi.stop << "'" << std::endl;
}
#include <boost/spirit.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

struct json_grammar
: public boost::spirit::grammar<json_grammar>
{
struct print
{
void operator()(const char *begin, const char *end) const
{
std::cout << std::string(begin, end) << std::endl;
}

void operator()(const double d) const


{
std::cout << d << std::endl;
}
};

template <typename Scanner>


struct definition
{
boost::spirit::rule<Scanner> object, member, string, value, number, array;

definition(const json_grammar &self)


{
using namespace boost::spirit;
object = "{" >> member >> *("," >> member) >> "}";
member = string[print()] >> ":" >> value;
string = "\"" >> *~ch_p("\"") >> "\"";
value = string | number | object | array | str_p("true")[print()] | "false" | "null";
number = real_p[print()];
array = "[" >> value >> *("," >> value) >> "]";
}

const boost::spirit::rule<Scanner> &start()


{
return object;
}
};
};

int main(int argc, char *argv[])


{
std::ifstream fs(argv[1]);
std::ostringstream ss;
ss << fs.rdbuf();
std::string data = ss.str();

json_grammar g;
boost::spirit::parse_info<> pi = boost::spirit::parse(data.c_str(), g, boost::spirit::space_p);
if (pi.hit)
{
if (pi.full)
std::cout << "parsing all data successfully" << std::endl;
else
std::cout << "parsing data partially" << std::endl;
std::cout << pi.length << " characters parsed" << std::endl;
}
else
std::cout << "parsing failed; stopped at '" << pi.stop << "'" << std::endl;
}
#include <boost/array.hpp>
#include <iostream>
#include <string>
#include <algorithm>

int main()
{
typedef boost::array<std::string, 3> array;
array a;

a[0] = "Boris";
a.at(1) = "Anton";
*a.rbegin() = "Caesar";

std::sort(a.begin(), a.end());

for (array::const_iterator it = a.begin(); it != a.end(); ++it)


std::cout << *it << std::endl;

std::cout << a.size() << std::endl;


std::cout << a.max_size() << std::endl;
}
#include <boost/array.hpp>
#include <string>

int main()
{
typedef boost::array<std::string, 3> array;
array a = { "Boris", "Anton", "Caesar" };
}
#include <boost/unordered_set.hpp>
#include <iostream>
#include <string>

int main()
{
typedef boost::unordered_set<std::string> unordered_set;
unordered_set set;

set.insert("Boris");
set.insert("Anton");
set.insert("Caesar");

for (unordered_set::iterator it = set.begin(); it != set.end(); ++it)


std::cout << *it << std::endl;

std::cout << set.size() << std::endl;


std::cout << set.max_size() << std::endl;

std::cout << (set.find("David") != set.end()) << std::endl;


std::cout << set.count("Boris") << std::endl;
}
#include <boost/unordered_map.hpp>
#include <iostream>
#include <string>

int main()
{
typedef boost::unordered_map<std::string, int> unordered_map;
unordered_map map;

map.insert(unordered_map::value_type("Boris", 31));
map.insert(unordered_map::value_type("Anton", 35));
map.insert(unordered_map::value_type("Caesar", 25));

for (unordered_map::iterator it = map.begin(); it != map.end(); ++it)


std::cout << it->first << ", " << it->second << std::endl;

std::cout << map.size() << std::endl;


std::cout << map.max_size() << std::endl;

std::cout << (map.find("David") != map.end()) << std::endl;


std::cout << map.count("Boris") << std::endl;
}
#include <boost/unordered_set.hpp>
#include <string>

struct person
{
std::string name;
int age;

person(const std::string &n, int a)


: name(n), age(a)
{
}

bool operator==(const person &p) const


{
return name == p.name && age == p.age;
}
};

std::size_t hash_value(person const &p)


{
std::size_t seed = 0;
boost::hash_combine(seed, p.name);
boost::hash_combine(seed, p.age);
return seed;
}

int main()
{
typedef boost::unordered_set<person> unordered_set;
unordered_set set;

set.insert(person("Boris", 31));
set.insert(person("Anton", 35));
set.insert(person("Caesar", 25));
}
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>

struct person
{
std::string name;
int age;

person(const std::string &n, int a)


: name(n), age(a)
{
}
};

typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, std::string, &person::name
>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, int, &person::age
>
>
>
> person_multi;

int main()
{
person_multi persons;

persons.insert(person("Boris", 31));
persons.insert(person("Anton", 35));
persons.insert(person("Caesar", 25));

std::cout << persons.count("Boris") << std::endl;

const person_multi::nth_index<1>::type &age_index = persons.get<1>();


std::cout << age_index.count(25) << std::endl;
}
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>

struct person
{
std::string name;
int age;

person(const std::string &n, int a)


: name(n), age(a)
{
}
};

typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, std::string, &person::name
>
>,
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, int, &person::age
>
>
>
> person_multi;

void set_age(person &p)


{
p.age = 32;
}

int main()
{
person_multi persons;

persons.insert(person("Boris", 31));
persons.insert(person("Anton", 35));
persons.insert(person("Caesar", 25));

person_multi::iterator it = persons.find("Boris");
persons.modify(it, set_age);

const person_multi::nth_index<1>::type &age_index = persons.get<1>();


std::cout << age_index.count(32) << std::endl;
}
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>

struct person
{
std::string name;
int age;

person(const std::string &n, int a)


: name(n), age(a)
{
}
};

typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
person, std::string, &person::name
>
>,
boost::multi_index::hashed_unique<
boost::multi_index::member<
person, int, &person::age
>
>
>
> person_multi;

int main()
{
person_multi persons;

persons.insert(person("Boris", 31));
persons.insert(person("Anton", 31));
persons.insert(person("Caesar", 25));

const person_multi::nth_index<1>::type &age_index = persons.get<1>();


std::cout << age_index.count(31) << std::endl;
}
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>

struct person
{
std::string name;
int age;

person(const std::string &n, int a)


: name(n), age(a)
{
}
};

typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>,
boost::multi_index::ordered_non_unique<
boost::multi_index::member<
person, int, &person::age
>
>,
boost::multi_index::random_access<>
>
> person_multi;

int main()
{
person_multi persons;

persons.push_back(person("Boris", 31));
persons.push_back(person("Anton", 31));
persons.push_back(person("Caesar", 25));
const person_multi::nth_index<1>::type &ordered_index = persons.get<1>();
person_multi::nth_index<1>::type::iterator lower = ordered_index.lower_bound(30);
person_multi::nth_index<1>::type::iterator upper = ordered_index.upper_bound(40);
for (; lower != upper; ++lower)
std::cout << lower->name << std::endl;

const person_multi::nth_index<2>::type &random_access_index = persons.get<2>();


std::cout << random_access_index[2].name << std::endl;
}
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <iostream>
#include <string>

class person
{
public:
person(const std::string &n, int a)
: name(n), age(a)
{
}

bool operator<(const person &p) const


{
return age < p.age;
}

std::string get_name() const


{
return name;
}

private:
std::string name;
int age;
};

typedef boost::multi_index::multi_index_container<
person,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::identity<person>
>,
boost::multi_index::hashed_unique<
boost::multi_index::const_mem_fun<
person, std::string, &person::get_name
>
>
>
> person_multi;

int main()
{
person_multi persons;

persons.insert(person("Boris", 31));
persons.insert(person("Anton", 31));
persons.insert(person("Caesar", 25));

std::cout << persons.begin()->get_name() << std::endl;

const person_multi::nth_index<1>::type &hashed_index = persons.get<1>();


std::cout << hashed_index.count("Boris") << std::endl;
}
#include <boost/bimap.hpp>
#include <iostream>
#include <string>

int main()
{
typedef boost::bimap<std::string, int> bimap;
bimap persons;

persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));

std::cout << persons.left.count("Boris") << std::endl;


std::cout << persons.right.count(31) << std::endl;
}
#include <boost/bimap.hpp>
#include <iostream>
#include <string>

int main()
{
typedef boost::bimap<std::string, int> bimap;
bimap persons;

persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));

for (bimap::iterator it = persons.begin(); it != persons.end(); ++it)


std::cout << it->left << " is " << it->right << " years old." << std::endl;
}
#include <boost/bimap.hpp>
#include <iostream>
#include <string>

int main()
{
typedef boost::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::set_of<int>> bimap;
bimap persons;

persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));

std::cout << persons.left.count("Boris") << std::endl;


std::cout << persons.right.count(31) << std::endl;
}
#include <boost/bimap.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <iostream>
#include <string>

int main()
{
typedef boost::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::multiset_of<int>> bimap;
bimap persons;

persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));

std::cout << persons.left.count("Boris") << std::endl;


std::cout << persons.right.count(31) << std::endl;
}
#include <boost/bimap.hpp>
#include <boost/bimap/unconstrained_set_of.hpp>
#include <boost/bimap/support/lambda.hpp>
#include <iostream>
#include <string>

int main()
{
typedef boost::bimap<std::string, boost::bimaps::unconstrained_set_of<int>> bimap;
bimap persons;

persons.insert(bimap::value_type("Boris", 31));
persons.insert(bimap::value_type("Anton", 31));
persons.insert(bimap::value_type("Caesar", 25));

bimap::left_map::iterator it = persons.left.find("Boris");
persons.left.modify_key(it, boost::bimaps::_key = "Doris");

std::cout << it->first << std::endl;


}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tuple<std::string, std::string> person;
person p("Boris", "Schaeling");
std::cout << p << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p("Boris", "Schaeling", 43);
std::cout << p << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <iostream>

int main()
{
std::cout << boost::make_tuple("Boris", "Schaeling", 43) << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>

int main()
{
std::string s = "Boris";
std::cout << boost::make_tuple(boost::ref(s), "Schaeling", 43) << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p = boost::make_tuple("Boris", "Schaeling", 43);
std::cout << p.get<0>() << std::endl;
std::cout << boost::get<0>(p) << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p = boost::make_tuple("Boris", "Schaeling", 43);
p.get<1>() = "Becker";
std::cout << p << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tuple<std::string, std::string, int> person;
person p1 = boost::make_tuple("Boris", "Schaeling", 43);
person p2 = boost::make_tuple("Boris", "Becker", 43);
std::cout << (p1 != p2) << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tuple<std::string&, std::string&, int&> person;

std::string firstname = "Boris";


std::string surname = "Schaeling";
int shoesize = 43;
person p = boost::tie(firstname, surname, shoesize);
surname = "Becker";
std::cout << p << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>

int main()
{
typedef boost::tuple<std::string&, std::string&, int&> person;

std::string firstname = "Boris";


std::string surname = "Schaeling";
int shoesize = 43;
person p = boost::make_tuple(boost::ref(firstname), boost::ref(surname), boost::ref(shoesize));
surname = "Becker";
std::cout << p << std::endl;
}
#include <boost/tuple/tuple.hpp>
#include <string>
#include <iostream>

boost::tuple<std::string, int> func()


{
return boost::make_tuple("Error message", 2009);
}

int main()
{
std::string errmsg;
int errcode;

boost::tie(errmsg, errcode) = func();


std::cout << errmsg << ": " << errcode << std::endl;
}
#include <boost/any.hpp>

int main()
{
boost::any a = 1;
a = 3.14;
a = true;
}
#include <boost/any.hpp>
#include <string>

int main()
{
boost::any a = 1;
a = 3.14;
a = true;
a = std::string("Hello, world!");
}
#include <boost/any.hpp>
#include <iostream>

int main()
{
boost::any a = 1;
std::cout << boost::any_cast<int>(a) << std::endl;
a = 3.14;
std::cout << boost::any_cast<double>(a) << std::endl;
a = true;
std::cout << boost::any_cast<bool>(a) << std::endl;
}
#include <boost/any.hpp>
#include <iostream>

int main()
{
try
{
boost::any a = 1;
std::cout << boost::any_cast<float>(a) << std::endl;
}
catch (boost::bad_any_cast &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/any.hpp>
#include <typeinfo>
#include <iostream>

int main()
{
boost::any a = 1;
if (!a.empty())
{
const std::type_info &ti = a.type();
std::cout << ti.name() << std::endl;
}
}
#include <boost/any.hpp>
#include <iostream>

int main()
{
boost::any a = 1;
int *i = boost::any_cast<int>(&a);
std::cout << *i << std::endl;
}
#include <boost/variant.hpp>

int main()
{
boost::variant<double, char> v;
v = 3.14;
v = 'A';
}
#include <boost/variant.hpp>
#include <string>

int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
v = 'A';
v = "Hello, world!";
}
#include <boost/variant.hpp>
#include <string>
#include <iostream>

int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
std::cout << boost::get<double>(v) << std::endl;
v = 'A';
std::cout << boost::get<char>(v) << std::endl;
v = "Hello, world!";
std::cout << boost::get<std::string>(v) << std::endl;
}
#include <boost/variant.hpp>
#include <string>
#include <iostream>

int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
std::cout << v << std::endl;
v = 'A';
std::cout << v << std::endl;
v = "Hello, world!";
std::cout << v << std::endl;
}
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <vector>
#include <string>
#include <iostream>

std::vector<boost::any> vector;

struct output :
public boost::static_visitor<>
{
void operator()(double &d) const
{
vector.push_back(d);
}

void operator()(char &c) const


{
vector.push_back(c);
}

void operator()(std::string &s) const


{
vector.push_back(s);
}
};

int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
boost::apply_visitor(output(), v);
v = 'A';
boost::apply_visitor(output(), v);
v = "Hello, world!";
boost::apply_visitor(output(), v);
}
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <vector>
#include <string>
#include <iostream>

std::vector<boost::any> vector;

struct output :
public boost::static_visitor<>
{
template <typename T>
void operator()(T &t) const
{
vector.push_back(t);
}
};

int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
boost::apply_visitor(output(), v);
v = 'A';
boost::apply_visitor(output(), v);
v = "Hello, world!";
boost::apply_visitor(output(), v);
}
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <string>

int main()
{
boost::system::error_code ec;
std::string hostname = boost::asio::ip::host_name(ec);
std::cout << ec.value() << std::endl;
}
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <string>

int main()
{
boost::system::error_code ec;
std::string hostname = boost::asio::ip::host_name(ec);
std::cout << ec.value() << std::endl;
std::cout << ec.category().name() << std::endl;
}
#include <boost/system/error_code.hpp>
#include <iostream>
#include <string>

class application_category :
public boost::system::error_category
{
public:
const char *name() const { return "application"; }
std::string message(int ev) const { return "error message"; }
};

application_category cat;

int main()
{
boost::system::error_code ec(14, cat);
std::cout << ec.value() << std::endl;
std::cout << ec.category().name() << std::endl;
}
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <string>

int main()
{
boost::system::error_code ec;
std::string hostname = boost::asio::ip::host_name(ec);
boost::system::error_condition ecnd = ec.default_error_condition();
std::cout << ecnd.value() << std::endl;
std::cout << ecnd.category().name() << std::endl;
}
#include <boost/asio.hpp>
#include <boost/system/system_error.hpp>
#include <iostream>

int main()
{
try
{
std::cout << boost::asio::ip::host_name() << std::endl;
}
catch (boost::system::system_error &e)
{
boost::system::error_code ec = e.code();
std::cerr << ec.value() << std::endl;
std::cerr << ec.category().name() << std::endl;
}
}
#include <boost/exception/all.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <exception>
#include <string>
#include <iostream>

typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info;

class allocation_failed :
public boost::exception,
public std::exception
{
public:
allocation_failed(std::size_t size)
: what_("allocation of " + boost::lexical_cast<std::string>(size) + " bytes failed")
{
}

virtual const char *what() const throw()


{
return what_.c_str();
}

private:
std::string what_;
};

boost::shared_array<char> allocate(std::size_t size)


{
if (size > 1000)
throw allocation_failed(size);
return boost::shared_array<char>(new char[size]);
}

void save_configuration_data()
{
try
{
boost::shared_array<char> a = allocate(2000);
// saving configuration data ...
}
catch (boost::exception &e)
{
e << errmsg_info("saving configuration data failed");
throw;
}
}

int main()
{
try
{
save_configuration_data();
}
catch (boost::exception &e)
{
std::cerr << boost::diagnostic_information(e);
}
}
#include <boost/exception/all.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <exception>
#include <string>
#include <iostream>

typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info;

class allocation_failed :
public std::exception
{
public:
allocation_failed(std::size_t size)
: what_("allocation of " + boost::lexical_cast<std::string>(size) + " bytes failed")
{
}

virtual const char *what() const throw()


{
return what_.c_str();
}

private:
std::string what_;
};

boost::shared_array<char> allocate(std::size_t size)


{
if (size > 1000)
BOOST_THROW_EXCEPTION(allocation_failed(size));
return boost::shared_array<char>(new char[size]);
}

void save_configuration_data()
{
try
{
boost::shared_array<char> a = allocate(2000);
// saving configuration data ...
}
catch (boost::exception &e)
{
e << errmsg_info("saving configuration data failed");
throw;
}
}

int main()
{
try
{
save_configuration_data();
}
catch (boost::exception &e)
{
std::cerr << boost::diagnostic_information(e);
}
}
#include <boost/exception/all.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <exception>
#include <string>
#include <iostream>

typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info;

class allocation_failed :
public std::exception
{
public:
allocation_failed(std::size_t size)
: what_("allocation of " + boost::lexical_cast<std::string>(size) + " bytes failed")
{
}

virtual const char *what() const throw()


{
return what_.c_str();
}

private:
std::string what_;
};

boost::shared_array<char> allocate(std::size_t size)


{
if (size > 1000)
BOOST_THROW_EXCEPTION(allocation_failed(size));
return boost::shared_array<char>(new char[size]);
}

void save_configuration_data()
{
try
{
boost::shared_array<char> a = allocate(2000);
// saving configuration data ...
}
catch (boost::exception &e)
{
e << errmsg_info("saving configuration data failed");
throw;
}
}

int main()
{
try
{
save_configuration_data();
}
catch (boost::exception &e)
{
std::cerr << *boost::get_error_info<errmsg_info>(e);
}
}
struct father
{
virtual ~father() { };
};

struct mother
{
virtual ~mother() { };
};

struct child :
public father,
public mother
{
};

void func(father *f)


{
child *c = dynamic_cast<child*>(f);
}

int main()
{
child *c = new child;
func(c);

father *f = new child;


mother *m = dynamic_cast<mother*>(f);
}
#include <boost/cast.hpp>

struct father
{
virtual ~father() { };
};

struct mother
{
virtual ~mother() { };
};

struct child :
public father,
public mother
{
};

void func(father *f)


{
child *c = boost::polymorphic_downcast<child*>(f);
}

int main()
{
child *c = new child;
func(c);

father *f = new child;


mother *m = boost::polymorphic_cast<mother*>(f);
}
#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>

int main()
{
std::string s = boost::lexical_cast<std::string>(169);
std::cout << s << std::endl;
double d = boost::lexical_cast<double>(s);
std::cout << d << std::endl;
}
#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>

int main()
{
try
{
int i = boost::lexical_cast<int>("abc");
std::cout << i << std::endl;
}
catch (boost::bad_lexical_cast &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <iostream>

int main()
{
int i = 0x10000;
short s = i;
std::cout << s << std::endl;
}
#include <boost/numeric/conversion/cast.hpp>
#include <iostream>

int main()
{
try
{
int i = 0x10000;
short s = boost::numeric_cast<short>(i);
std::cout << s << std::endl;
}
catch (boost::numeric::bad_numeric_cast &e)
{
std::cerr << e.what() << std::endl;
}
}
#include <boost/numeric/conversion/cast.hpp>
#include <iostream>

int main()
{
try
{
int i = -0x10000;
short s = boost::numeric_cast<short>(i);
std::cout << s << std::endl;
}
catch (boost::numeric::negative_overflow &e)
{
std::cerr << e.what() << std::endl;
}
}

Potrebbero piacerti anche