vector<int> v {3, 5, 2};
list<int> l {2, 7, 8, 9}; 
int a[10];
auto pa = copy(v.begin(), v.end(), a);
pa = copy(l.begin(), l.end(), pa);
Что будет, если в том контейнере куда мы копируем будет недостаточно места? Будет перезаписана чужая память из-за отсутствия контроля выхода за границу.
Если написать так:
pa = copy(l.end(), l.begin(), pa);
Тогда copy от такой ошибки не застрахован, так же он не застрахован от ошибок в случае такого кода:
pa = copy(l.end(), l.begin(), pa);
pa = copy(l.begin(), l1.end(), pa);
Замечание. Важно помнить, что элемент, на который указывает end() не принадлежит контейнеру, в отличии от begin(), который является итератором на первый элемент контейнера.
Мы хотим, что copy работал и для списка.
Для работы класса list_iterator нужен listnode<T>
Перегружая операции в copy мы изменяем работу copy. Сколько типов мы определим, столько будет создано copy
template<typename T>
class list_iterator
{
    listnode<T> * cur;
public:
    list_iterator(listnode<T>* c):cur(c){}
    T& operator*() {eturn cur->data;}
    listierator<T>& operator++()
    {
        cur = cur->next;
        return *this;
    }
    template<typename S>
    friend bool operator!=(list_iterator<S>i1, list_iterator<S>i2)
    {
        return i1.cur != i2.cur;
    }
};
Теперь copy будет выглядеть следующим образом
template<typename It, typename It1>
OutIt copy(InIt b, InIt e, OutIt b1)
{
    while(b.cur != e.cur)
        *b1 = b.cut->data;
    ++b1;
    b.cur = b.cur->next;
    return b1;
}
vector<T> - внутри это массивlist<T> - внутри это двусвязный списокstack<T> - различная реализация контейнераqeueu<T> - различная реализация контейнераdeque<T> - это абстрактный тип данных с эффективными операциями доступа к началу и конку и достаточно эффективной операцией доступа по индексуАссоциативные контейнеры:
map<K, V> - это аналог SortedDicionary<K, V> в .NET, по сути бинарное дерево поиска, то есть скорость поиска log(n)set<K> - множество, так же является бинарным деревом поиска multimap<K,V> - map с повторяющимися значениямиmultiset<K> - set с повторяющимися ключамиunordered_map<K, V> - хеш-таблица O(1)unordered_set<K> - хеш-таблица O(1)vector<int> {2, 5, 1, 3};
list<int> {2, 5, 1, 3};
set<int> {2, 5, 1, 3};
// Инициализация диапазоном другого контейнера
int a[]{1, 2, 4, 5, 6};
vector<int> v1(a, a + 3);
v = v1;
l = l1; // присваивание возможно только для объектов одного типа
// Расширенное присваивание
v.assign(l.begin(), l.end());
// Перевыделение памяти
v1 < v2; // Лексикографическое сравнение
for_eachРабота:
#include <algorithm>
template<typename InIt, typename Fun>
Fun for_each(InIt b, InIt e, Fun f)
{
    while(b != e)
    {
        f(*b);
        ++b;
    }
    return f;
}
Использование:
// Печать элемента контейнера
void print(int i)
{
    cout << i << " ";
}
list<int> l{1, 3, 5};
for_each(l.begin(), l.end(), print);
Тот же код можно написать с использованием лямбда выражений:
for_each(l.begin(), l.end(), [](int i){cout << i << " ";});
В STL вызов for_each имеет следующий вид:
Fun for_each(InIt first, InIt last, Fun f);
Здесь InIt = list<int>::iterator, Fun = void(*)(int)