Cserép Máté
I am a researcher and lecturer in computer science with several years of experience in object-oriented design and development. I have an application development experience primarily in C++, the C#/.NET technologies, PHP and Python.
Máté Cserép
October 2015, Budapest
Alexander Stepanov:
Part of the C++ standard. The most important example for generic programming. Generic programming: make more abstract routines without loosing efficiency using parameterization (both data and algorithm).
// Find the first occurrence of a value
int t[] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
int *p = find(t, t + sizeof(t) / sizeof(t[0]), 11);
if(p)
{
p = 12;
}
// Specific implementation for arrays
int *find(int *begin, int *end, int v)
{
while (begin != end )
{
if (*begin == v)
{
return begin;
}
++begin;
}
return 0;
}
Motivation
template <typename T>
T *find(T *begin, T *end, const T& v)
{
while (begin != end)
{
if (*begin == v)
{
return begin;
}
++begin;
}
return 0;
}
template <typename It, typename T>
It find( It begin, It end, const T& v)
{
while (begin != end)
{
if (*begin == v)
{
return begin;
}
++begin;
}
return end;
}
Generalization on type int -> T
Generalization on data structure
int t[] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
int *p = find(t, t + sizeof(t) / sizeof(t[0]), 11);
if(p)
{
p = 12;
}
vector<int> v;
v.push_back(1); v.push_back(3); v.push_back(5); v.push_back(7); v.push_back(9);
v.push_back(11); v.push_back(13); v.push_back(15); v.push_back(17); v.push_back(19);
vector<int>::iterator vi = find(v.begin(), v.end(), 11);
if (vi != v.end())
{
*vi = 12;
}
list<double> l;
l.push_back(1.1); l.push_back(3.3); l.push_back(5.5); l.push_back(7.7); l.push_back(9.9);
l.push_back(11.11); l.push_back(13.13); l.push_back(15.15); l.push_back(17.17); l.push_back(19.19);
list<double>::iterator li = find(l.begin(), l.end(), 11.11);
if (li != l.end())
{
*li = 12.12;
}
Uniform usage
const int t[] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
const int *pi = find(t, t + sizeof(t) / sizeof(t[0]), 11);
if (pi)
{
//*pi = 12; // Syntax error
cout << *pi;
}
vector<int> v;
v.push_back(1.1); v.push_back(3.3); v.push_back(5.5); v.push_back(7.7); v.push_back(9.9);
v.push_back(11.11); v.push_back(13.13); v.push_back(15.15); v.push_back(17.17); v.push_back(19.19);
const list<double> cl(v.begin(), v.end());
// const_iterator != const iterator
list<double>::const_iterator cli = find(cl.begin(), cl.end(), 11.11);
if (cli != cl.end())
{
//*cli = 12.12; // Syntax error
cout << *cli;
}
Constant safety
// Find the 3rd occurrence:
list<double> l;
l.push_back(1.1); l.push_back(3.3);
l.push_back(5.5); l.push_back(7.7);
l.push_back(9.9); l.push_back(11.11);
l.push_back(13.13); l.push_back(15.15);
l.push_back(17.17); l.push_back(19.19);
list<double>::iterator li;
li = find(l.begin(), l.end(), 3.14);
li = find(li, l.end(), 3.14);
li = find(li, l.end(), 3.14);
// or:
li = find(find(find(l.begin(), l.end(), 3.14),
l.end(), 3.14),
l.end(), 3.14);
template <typename It, typename Pred>
It find_if(It begin, It end, Pred p)
{
while (begin != end)
{
if ( p(*begin) )
{
return begin;
}
++begin;
}
return end;
}
// Pred1: not too good
bool less55_3rd( int x)
{
static int cnt = 0;
if ( x < 55 )
++cnt;
return 3 == cnt;
}
vector<int> v;
v.push_back(1); v.push_back(3);
v.push_back(5); v.push_back(7);
v.push_back(9); v.push_back(11);
v.push_back(13); v.push_back(15);
v.push_back(17); v.push_back(19);
vector<int>::iterator =
find_if(v.begin(), v.end(), less55_3rd);
vector<int>::iterator =
find_if(v.begin(), v.end(), less55_3rd);
Predicates
// Pred2: functor instead of function
struct less55_3rd
{
less55_3rd() : cnt(0) { }
bool operator()(int x)
{
if ( x < 55 )
++cnt;
return 3 == cnt;
}
private:
int cnt;
};
vector<int> v;
v.push_back(1); v.push_back(3);
v.push_back(5); v.push_back(7);
v.push_back(9); v.push_back(11);
v.push_back(13); v.push_back(15);
v.push_back(17); v.push_back(19);
less55_3rd pp;
vector<int>::iterator =
find_if(v.begin(), v.end(), pp);
// or:
vector<int>::iterator =
find_if(v.begin(), v.end(), less55_3rd());
Predicates
// Pred3: more generic
template <typename T>
struct less_nth
{
less_nth(const T& t, int n)
: _t(t), _n(n), _cnt(0) { }
bool operator()(const T& t)
{
if (t < _t)
++cnt;
return _n == cnt;
}
private:
T _t;
int _n;
int _cnt;
};
vector<int> v;
v.push_back(1); v.push_back(3);
v.push_back(5); v.push_back(7);
v.push_back(9); v.push_back(11);
v.push_back(13); v.push_back(15);
v.push_back(17); v.push_back(19);
vector<int>::iterator =
find_if(v.begin(), v.end(),
less_nth<int>(55,3));
Predicates
Part of the C++ standard. The most important example for generic programming. Generic programming: make more abstract routines without loosing efficiency using parameterization (both data and algorithm).
Components:
template<class InputIt, class T>
InputIt find(InputIt first, InputIt last, const T& value)
{
for (; first != last; ++first) {
if (*first == value) {
return first;
}
}
return last;
}
Categories
Types
stack
Op: empty, size, back (->top), push_back (->push), pop_back (->pop)
Cont: deque (default), vector, list
queue
Op: empty, size, front, back, push_back (->push), pop_front (->pop)
Cont: deque (default), list
priority_queue
Op: empty, size, front, push_back (->push), pop_back (->pop)
Cont: vector (default), deque
Beside these, they have a pretty much common interface.
vector:
deque:
list:
ordered associative:
unordered associative:
vector | deque | list | |
---|---|---|---|
typical internal data structure | dynamic array | array of arrays | doubly linked list |
elements | value | value | value |
duplicates allowed | yes | yes | yes |
random access | yes | yes | no |
iterator category | random | random | bidirectional |
search/find element | slow | slow | very slow |
fast insert/remove | at end | at front & at end | anywhere |
inserting/removing invalidates iterator, ptr, ref | on reallocation | always | never |
frees memory for removed elements | never | sometimes | always |
allows memory reservation | yes | no | --- |
transaction safe exception safe |
push_back() pop_back() |
push_back() pop_back() push_front() pop_front() |
all except sort() |
Sequential
set | multiset | map | multimap | |
---|---|---|---|---|
typical internal data structure | binary tree | binary tree | binary tree | binary tree |
elements | value | value | key/value | key/value |
duplicates allowed | no | yes | no | yes |
random access | no | no | with key | no |
iterator category | bidirectional | bidirectional | bidirectional | bidirectional |
search/find element | fast | fast | fast (key) | fast (key) |
fast insert/remove | --- | --- | --- | --- |
inserting/removing invalidates iterator, ptr, ref | never | never | never | never |
frees memory for removed elements | always | always | always | always |
allows memory reservation | --- | --- | --- | --- |
transaction safe exception safe |
all except multiple element insert() |
all except multiple element insert() |
all except multiple element insert() |
all except multiple element insert() |
Ordered associative
unordered_set | unordered_multiset | unordered_map | unordered_multimap | |
---|---|---|---|---|
typical internal data structure | hash table | hash table | hash table | hash table |
elements | value | value | key/value | key/value |
duplicates allowed | no | yes | no | yes |
random access | no | no | with key | no |
iterator category | forward | forward | forward | forward |
search/find element | fast | fast | fast (key) | fast (key) |
fast insert/remove | --- | --- | --- | --- |
inserting/removing invalidates iterator, ptr, ref | never | never | never | never |
frees memory for removed elements | never | never | never | never |
allows memory reservation | yes | yes | yes | yes |
transaction safe exception safe |
all except multiple element insert() |
all except multiple element insert() |
all except multiple element insert() |
all except multiple element insert() |
Unordered associative
By Cserép Máté
I am a researcher and lecturer in computer science with several years of experience in object-oriented design and development. I have an application development experience primarily in C++, the C#/.NET technologies, PHP and Python.