Book Image

Boost C++ Application Development Cookbook - Second Edition

By : Anton Polukhin Alekseevic
Book Image

Boost C++ Application Development Cookbook - Second Edition

By: Anton Polukhin Alekseevic

Overview of this book

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

Returning a value or flag where there is no value


Imagine that we have a function that does not throw an exception and returns a value or indicates that an error has occurred. In Java or C# programming languages, such cases are handled by comparing a return value from a function value with a null pointer. If the function returned null, then an error has occurred. In C++, returning a pointer from a function confuses library users and usually requires slow dynamic memory allocation.

Getting ready

Only basic knowledge of C++ is required for this recipe.

How to do it...

Ladies and gentlemen, let me introduce you to the Boost.Optional library using the following example:

The try_lock_device() function tries to acquire a lock for a device and may succeed or not, depending on different conditions (in our example it depends on some try_lock_device_impl() function call):

#include <boost/optional.hpp>
#include <iostream>

class locked_device {
    explicit locked_device(const char* /*param*/) {
        // We have unique access to device.
        std::cout << "Device is locked\n";
    }

    static bool try_lock_device_impl();

public:
    void use() {
        std::cout << "Success!\n";
    }

    static boost::optional<locked_device> try_lock_device() {
        if (!try_lock_device_impl()) {
            // Failed to lock device.
            return boost::none;
        }

        // Success!
        return locked_device("device name");
    }

    ~locked_device(); // Releases device lock.
};

The function returns the boost::optional variable that can be converted to a bool. If the returned value is equal to true, then the lock is acquired and an instance of a class to work with the device can be obtained by dereferencing the returned optional variable:

int main() { 
    for (unsigned i = 0; i < 10; ++i) { 
        boost::optional<locked_device> t
            = locked_device::try_lock_device(); 

        // optional is convertible to bool.
        if (t) { 
            t->use(); 
            return 0; 
        } else { 
            std::cout << "...trying again\n"; 
        } 
    } 

    std::cout << "Failure!\n"; 
    return -1; 
} 

This program will output the following:

...trying again
...trying again
Device is locked
Success!

Note

The default constructed optional variable is convertible to false and must not be dereferenced, because such an optional does not have an underlying type constructed.

How it works...

boost::optional<T> under the hood has a properly aligned array of bytes where the object of type T can be an in-place constructed. It also has a bool variable to remember the state of the object (is it constructed or not?).

There's more...

The Boost.Optional class does not use dynamic allocation and it does not require a default constructor for the underlying type. The current boost::optional implementation can work with C++11 rvalue references but is not usable with constexpr.

Note

If you have a class T that has no empty state but your program logic requires an empty state or uninitialized T, then you have to come up with some workaround. Traditionally, users create some smart pointer to the class T, keep a nullptr in it, and dynamically allocate T if non empty state is required. Stop doing that! Use boost::optional<T> instead. It's a much faster and more reliable solution.

The C++17 standard includes the std::optional class. Just replace <boost/optional.hpp> with <optional> and boost:: with std:: to use the standard version of this class. std::optional is usable with constexpr.

See also

Boost's official documentation contains more examples and describes advanced features of Boost.Optional (like in-place construction). The documentation is available at the following link: http://boost.org/libs/optional.