Standard Template Library

Objectives

- Architecture

Architecture

C/C++ types are poor, and are mostly just a thin layer on top of the memory representation. This problem is especially acute with arrays and other data structures.

STL is a library providing both containers (such as vector) as well as algorithms, by means of the C++ templates with its main concern being performance and correctness.

 

Using templates solves the problem of implementing an algorithm for each of the possible types (Including user defined types)

But, The main STL challenge was the MxN problem ,with N containers and M algorithms. 

 

 

Architecture - cont

How to avoid coding algorithms for each of the containers ?

Inheritance has 2 problems 

- Inheriting from some base container has run time + space costs

- Although containers have overlapping behaviour it's not 100% compatible.

 

The solution that was chosen to avoid having to code algorithms for each of the containers is to entirely decouple the two and add another layer of abstraction in between

Containers

Algorithms

Iterators

Functors

Iterators

Iterators are pointer like abstraction to an element within a container

int arr[] = {1,2,3};
int* pI = &arr[0];

*pI = 10; // sets the first element of arr to 10
++pI;     // Advance pI to next element  
vector<int> v {1,2,3};
vector<int>::iterator itr = v.begin();

*itr = 10; // sets the first element of v to 10
++itr;     // Advance itr to next element  

Similar semantics for Iterators 

begin()

end()

1

3

2

Container

Iterators - cont

In fact arrays and containers can be used interchangeably 

    int arr[] = {1,2,3};
    
    for(int* p = &arr[0]; p != &arr[0] + 3; ++p)
        cout << *p <<endl;
    
    for_each(&arr[0], &arr[0] + 3, [](int n) { cout << n << endl; } );
    
    vector<int> v {11,22,33};
    for(vector<int>::iterator itr = v.begin(); itr != v.end(); ++itr)
        cout << *itr << endl;
        
    for_each(v.begin(), v.end(), [](int n) { cout << n << endl; } );    

Iterators categories

there are 5 Iterators categories identifying the operations they support

  • Input iterator: Only forward and one-pass, and only read
  • Output iterator: Only forward and one-pass, and only write

 

  • Forward iterator: Only forward, and read/write
  • Bidirectional iterator: Forward and backward, and read/write
  • Random access iterator: Arbitrary steps forward and backward in one breath, and read/write

 

Each iterator from the second group supports all the functionality in iterators mentioned before it.

 

C Pointer is considered a Random access iterator because it support all the operations a random access iterator dictates.

Containers

There are 2 types of containers

  • Sequence  
    • array
    • vector
    • deque - double ended queue (FIFO/LIFO)
    • list 
    • stack (LIFO)
    • forward_list
  • Associative 
    • map
    • multimap
    • set
    • Multiset
    • ​unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset 

Sequence containers

The user controls the order of the elements.

The vector<> is by far the most useful, and a replacement to the C array.

 

arrayvector and deque all support fast random access to the elements. list supports bidirectional iteration, whereas forward_list supports only unidirectional iteration.

 

array does not support element insertion or removal. 

vector supports fast element insertion or removal at the end. Any insertion or removal of an element not at the end of the vector needs elements between the insertion position and the end of the vector to be copied

 

Vector: Add  - O(1)   remove - O(N^2)   Random Access - O(1)

 

Associative containers

The order of the containers is dictated by the values.

 

  1. map, multimap, set, multiset - Implemented using Binary tree
  2. unordered family are implemented using Hash

 

The first group requires the less than operator to be implemented, and is applying a strict weak ordering

The second requires a good hash function + Equality predicate

 

 

Map

Maps element are pair<T1,T2> ordering is performed on T1

 

multimap, set, multiset do not have operator[]

 

Algorithms

include <algorithm>

Possible division:

  • Non-modifing (i.e count, find)
    • Equal - test equality of interval
    • all_of, any_of, none_of
  • Mutating  (i.e replace, transform)
    • copy
  • Sorting operations or variations (binary sort)
    • binary_search - returns bool, std::lower_bound vs std::upper_bound vs equal_range
    • stable_sort vs sort
    • partial_sort
    • nth_element
    • minmax_element

Range insertion over back_inserter

Made with Slides.com