Adding elements to our container

With our constructors in place, we will also need to provide the ability to manually add data to our container (for example, if we initially created our container using the default constructor).

To start, let's focus on the push_back() function that std::vector provides:

    void push_back(const T &value)
{
m_v.push_back(value);
std::sort(m_v.begin(), m_v.end(), compare_type());

std::cout << "1 ";
}

void push_back(T &&value)
{
m_v.push_back(std::move(value));
std::sort(m_v.begin(), m_v.end(), compare_type());

std::cout << "2 ";
}

As shown in the preceding code snippet, the push_back() function has the same function signatures as the version std::vector provides, allowing us to simply forward the function call to std::vector. The problem is, pushing a value to the end of std::vector could result in std::vector entering an unordered state, requiring us to reorder std::vector on every single push (the result of requiring std::vector to remain in sorted order at all times).

One way to resolve this issue is by adding another member variable to the container wrapper that tracks when the std::vector is tainted. Another way to implement these functions is to add the elements in a sorted order (that is, traverse the vector sorted order and place the element in the proper position, shifting the remaining elements as needed). If elements are rarely added to the std::vector, then this approach might outperform a call to std::sort. If, however, elements are added to the std::vector a lot, then the tainted approach might perform better.

One of the key benefits of creating a container wrapper is that these types of optimizations can be implemented and tested without changing the code that relies on the container itself. Both implementations (or others) can be implemented, tested, and compared to determine which optimization is best suited to your particular needs, while the code that uses the container never changes. Not only does this declutter the code, but this added encapsulation strikes at the heart of object-oriented design, ensuring that each object in your code has only one purpose. In the case of the container wrapper, the purpose is to encapsulate the operation of maintaining std::vector in sorted order.

For completeness, we will also add the emplace_back() version of push_back(), just like std::vector:

    template<typename... Args>
void emplace_back(Args&&... args)
{
m_v.emplace_back(std::forward<Args>(args)...);
std::sort(m_v.begin(), m_v.end(), compare_type());

std::cout << "3 ";
}

The difference with the emplace_back() function compared to the std::vector equivalent is that our version does not return a reference to the element created. This is because of the fact that the sort would invalidate the reference, making it impossible to return a valid reference.

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

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