How it works...

In this recipe, we will learn how to create a simple wrapper container around std::vector. Most of the time, the Standard Template Library (STL) containers are sufficient to perform the tasks that your applications might need, and, in general, creating your own containers should be avoided as they are complicated to get right.

From time to time, however, you might find yourself repeatedly performing the same actions on a container. When this occurs, it is often helpful to wrap these common operations into a wrapper container that can be independently unit tested to ensure that the container works as expected. For example, the STL containers are not thread safe. If you need a container to function with thread safety each time you access the container, you will first need to ensure that you have exclusive access to the container (for example, by locking a std::mutex) before the container operation can take place. This pattern will be repeated throughout your code, increasing the chances of entering deadlock. This issue can be prevented by creating a container wrapper that adds a std::mutex to each public member of the container.

In this recipe, let's consider an example where we create a vector (that is, an array of elements in contiguous memory that you must have direct access to) that must remain in sorted order at all times. To start, we will need some headers:

#include <vector>
#include <algorithm>
#include <iostream>

To implement our container, we will leverage std::vector. Although we could implement our own container from scratch, most of the time this is not needed, and should be avoided, as such a task is extremely time consuming and complicated. We will need the algorithm header for std::sort and iostream for testing. So let's add this as follows:

template<
typename T,
typename Compare = std::less<T>,
typename Allocator = std::allocator<T>
>
class container
{
using vector_type = std::vector<T, Allocator>;
vector_type m_v;

public:

The container's definition will start with its template definition, which is the same as the definition of the std::vector with an added Compare type that will be used to define the order in which we would like our container to be sorted. By default, the container will be sorted in ascending order, but this can be changed as needed. Finally, the container will have one private member variable that is an instance of the std::vector that this container is wrapping.

For the container to function properly with C++ utilities, template functions, and even some key language features, the container will need to define the same aliases as std::vector, shown as follows:

    using value_type = typename vector_type::value_type;
using allocator_type = typename vector_type::allocator_type;
using size_type = typename vector_type::size_type;
using difference_type = typename vector_type::difference_type;
using const_reference = typename vector_type::const_reference;
using const_pointer = typename vector_type::const_pointer;
using compare_type = Compare;

As you can see, there is no need to manually define the aliases ourselves. Instead, we can simply forward the declaration of the aliases from the std::vector itself. The exception to this is the compare_type alias, as this is an alias that we are adding to our wrapper container that represents the type used by the template class for the comparison operation that will ultimately be given to std::sort.

We also do not include the non-const versions of the reference aliases. The reason for this is that our container must keep the std::vector in sorted order at all times. If we provide the user with direct write access to the elements stored within std::vector, the user could put std::vector into an unordered state without our custom container having the ability to reorder as needed.

Next, let's define our constructors (which map to the same constructors that std::vector provides).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset