Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there a separation of algorithms, iterators and containers in C++ STL

I can't figure out why they have separated algorithms, iterators and containers in C++ STL. If it's a heavy use of templates everywhere, then we can have classes having all stuff in one place with template parameters.

Some text that I got explains that iterators helps algorithms to interact with containers data but what if containers expose some mechanism to access the data it possesses?

like image 310
Rahul Avatar asked Aug 14 '12 06:08

Rahul


People also ask

What is STL briefly explain the use of containers vectors lists?

The Standard Template Library (STL) is a set of C++ template classes to provide common programming data structures and functions such as lists, stacks, arrays, etc. It is a library of container classes, algorithms, and iterators. It is a generalized library and so, its components are parameterized.

What are the major components of STL explain in detail?

STL contains five kinds of components: containers, iterators, algorithms, function objects and allocators.

Why is the iterator class definition for each container nested within the container itself?

The internal behavior of iterators depends on the data structure over which they iterate. So, each container type provides its own kind of iterator. In fact, each container class defines its iterator type as a nested class. As a result, iterators share the same interface but have different types.


1 Answers

With M containers + N algorithms, one would normally need M * N pieces of code, but with iterators acting as "glue", this can be reduced to M + N pieces of code.

Example: run 2 algorithms on 3 containers

std::list<int> l = { 0, 2, 5, 6, 3, 1 }; // C++11 initializer lists
std::vector<int> v = { 0, 2, 5, 6, 3, 1 };  // C++11 initializer lists
std::array<int, 5> a = { 0, 2, 5, 6, 3, 1 };

auto l_contains1 = std::find(l.begin(), l.end(), 1) != l.end();
auto v_contains5 = std::find(v.begin(), v.end(), 5) != v.end();
auto a_contains3 = std::find(a.begin(), a.end(), 3) != a.end();

auto l_count1 = std::count(l.begin(), l.end(), 1);
auto v_count5 = std::count(v.begin(), v.end(), 5);
auto a_count3 = std::count(a.begin(), a.end(), 3);

You are calling only 2 different algorithms, and only have code for 3 containers. Each container passes the begin() and end() iterators to the container. Even though you have 3 * 2 lines of code to generate the answers, there are only 3 + 2 pieces of functionality that need to be written.

For more containers and algorithms, this separation is an enormous reduction in the combinatorial explosion in code that would otherwise ensue: there are 5 sequence containers, 8 associative containers and 3 container adapters in the STL, and there are almost 80 algorithms in <algorithm> alone (not even counting those in <numeric>) so that you have only 16 + 80 instead of 16 * 80, an 13-fold reduction in code! (Of course, not every algorithm makes sense on every container, but the point should be clear).

The iterators can be divided into 5 categories (input, output, forward, bidirectional and random access), and some algorithms will delegate to specialized versions depending on the iterator capabilities. This will diminish the code reduction somewhat, but greatly improve efficiency by selecting the best adapted algorithm to the iterator at hand.

Note that the STL is not completely consistent in the separation: std::list has its own sort member function that uses implementation specific details to sort itself, and std::string has an enormous number of member function algorithms, most of which could have been implemented as non-member functions.

like image 119
TemplateRex Avatar answered Oct 15 '22 15:10

TemplateRex