Reading the book on STL, I ran into the term adapter and immediately got into the search engine to highlight this question and did not find anything useful.

The book says that this is the implementation of one type of container by another type of container. In general, a little clear.

Tell us in your own words what an adapter is in STL.

    2 answers 2

    I want to start with a small preface: there is no such thing as STL in C ++, there is a standard library and this term should be followed. Previously, the term STL was used to refer to the standard library, but now it is considered a move.

    What is an adapter? This is essentially an established pattern that comes to us from the real world. We take one entity and adapt it to new conditions through another entity. Of course, it was not clearer.

    What is meant in the book? Probably there is talk about the stack and other container adapters. Why are they adapters? Because inside of them they use full-fledged containers, such as std::vector and std::deque , and adapt their interface to a different interface . For example, std::vector has push_back , insert and pop_back , but such operations are not needed for the stack, the stack needs 3 operations (basic) top , pop and push . But all these operations are implemented through the corresponding operations std::vector , which is hidden in the depths of std::stack . Therefore, stack not allocated as an independent container - it is an adapter for std::vector .

    In other words: an adapter is a concept that goes far beyond the standard C ++ library and, in general, can be neglected when studying C ++, since whether the container is an adapter or not is not a key part. It is interesting to know, but no more.

    • Thank you. very helpful. and I already thought that the adapter is just the vector in the stack so called, and then just the opposite is a container using an auxiliary container. - perfect
    • @perfect, do not try to narrow down the understanding only with these containers, it will only confuse you more. For example, if you have a stove with a triangular "entrance" and a round fireplace, which is less than this entrance. So, to more efficiently heat the pot, you can make a triangular adapter . Which will hide in itself a round pan and will be just under the “interface” of our furnace - ixSci
    • All right, I stack and vector just cited as an example. Besides, the answer to this question will now appear on the net - perfect

    Adapt means to adapt. That is, to adapt an existing entity, container, iterator, etc., in a new context or for a particular task.

    For example, the standard container double-linked list std::list has such methods as push_back , push_front , pop_back , pop_front , front, back .

    Using only a subset of the methods provided by the std::list container, you can simulate the behavior of a data structure such as a stack.

    In the data structure, the data stack is organized according to the principle: the last one entered the stack - the first one left the stack, that is, LIFO (last in, first out).

    Usually the stack methods of the container get the names push , pop , top , as, for example, in C ++, or Push , Pop , Peek , as, for example, in C # or other names. But regardless of the assigned method names, their behavior is semantically the same.

    To build a stack in C ++, it suffices to use the methods of either push_front , pop_front , front , or push_back , pop_back , back respectively, for the stack methods push , pop , top .

    To do this, simply in the implementation of these methods of the stack should call the appropriate methods of the container std::list .

    For example, the pop stack method can be implemented as a call to the corresponding container method std::list , which in the examples is indicated by the name c from the English word container :

     void pop() { c.pop_back(); } 

    or

     void pop() { c.pop_front(); } 

    Therefore, there is no need to define container data management stack. All data management will be done by the std::list container. Simply, its methods are, in fact, renamed to adapt to the names of the methods of the container stack.

    Therefore, the stack is not implemented from scratch, but it is simply an adaptation of the class std::list for the logic of the stack, that is, the stack is a container adapter .

    To make it possible to adapt as many consecutive containers as possible, it was agreed to limit the methods of sequential containers push_back , pop_back , and back , since these methods are more widely distributed among sequential containers. For example, the std::vector container does not have push_front and pop_front , so it could not be used to model stack methods using these methods of sequential containers.

    However, the standard sequential container std::forward_list , which was introduced in the C ++ standard after the rest of the standard standard containers, does not have the push_back , pop_back and back methods. Therefore, the container adapter std::stack cannot adapt this container to implement the stack.

    Nevertheless, I have already suggested that the C ++ Standardization Committees include a specialization of the std::stack class for the std::forward_list . This is not a fundamental difficulty to do.

    There is only one inconsistency: the std::forward_list does not have a size method that is present in the std::stack container adapter. From my point of view, this is not important.

    A similar approach is used for iterator adapters. An example of such an iterator adapter is std::reverse_iterator . It adapts the operator operator -- other iterators so that when operator ++ used, the operator operator ++ is actually called. This allows you to iterate through the elements of a container or sequence in reverse order, without changing the code, which is based on the application operator ++ .

    For example, if you have a function that streams the elements of a container by passing a range of elements to the function using two iterators, such as

     template <class ForwardIterator> std::ostream & display( ForwardIterator first, ForwardIterator last, std::ostream &os = std::cout ) { for ( ; first != last; ++first ) { os << *first << ' '; } return os; } 

    By passing in reverse iterators, you could, for example, output the elements of an array of integers in the reverse order:

     #include <iostream> #include <iterator> template <class ForwardIterator> std::ostream & display( ForwardIterator first, ForwardIterator last, std::ostream &os = std::cout ) { for ( ; first != last; ++first ) { os << *first << ' '; } return os; } int main() { const size_t N = 10; int a[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; display( a, a + N ) << std::endl; display( std::reverse_iterator<int *>( a + N ), std::reverse_iterator<int *>( a ) ) << std::endl; } 

    The output of the program to the console:

     0 1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 0 

    In this program, the std::reverse_iterator iterator adapter adapts int * type pointers for operations on them in the reverse order of the array elements. It uses those pointer methods that are already defined and exist for pointers.

    For a change as another example of the adapter of iterators, you can get acquainted with the iterator adapter iterator_pair that I proposed, which I described in my article in ACCU Overload # 126 magazine or via the links on my personal page here and here