История изменений
Исправление Dudraug, (текущая версия) :
На примере std::map.
Шаблоны и оопшность позволяют лаконично и универсально реализовать следующие:
1) Мы можем написать свой аллакатор. Например если мы знаем макс кол-во элементов в мапе, то мы можем написать аллокатор на статическом буфере. Это может позволить нам исбежать вызовов к ос, выделения памяти на хипе. Что сделать аллокация а) быстрее; б) более предсказуемую по продолжительности. Аллокация будет занимать константное время. А можно не париться и использовать стандартный аллокатор. Для этого(случая когда тебе надо алоцироваться не на хипе) тебе надо написать только аллокатор, без миллионов строк кода.
2) В мапе есть операция сравнения с помощью которой и происходит поиск элементов в ней. В общем случае это операция <. Но ты можешь определить свою операцию например для изменения порядка сортировки, или для особого сравнения(например с игноирированием регистра), или есл операции сравнения нет в принципе для типа ключа. И сделать ты это можешь тоже очень лаконично и просто.
3) Ты можешь описать любую мапу просто как std::map<Tkey, TVal> mp; не запариваясь вообще о доп коде для новых типов (с некоторыми оговорками, но которые не актуальны в большинстве случаев)
4) Ты можешь создать мапу(как в прочем и вектор, и список, и сет, и std::array) из двух итераторов на рендж того же типа. А итератором является в том числе и указатели на элементы обычного массива
Ниже пример правда для сета:
char buf[255];
FillBuf(buf, 255);
std::set<char> st(buf, buf+255);
5) Доп пример, при помощи шаблонов ты можешь писать обертки например для случаев когда тебе надо использовать выравненые данные
Вместо
void f(int* ptr, size_t data) {....} //PLEASE USE ALIGINED DATA(by 32bytes)
Это
template<class T, size_t SZ>
struct ABuf {
T buf[SZ] __attribute__ ((aligned (32)));
};
void f_impl(int* buf, size_t sz) {....}
template<size_t SZ>
inline void f(ABuf<int, SZ>& buf) {f_impl(buf.buf, SZ);}
Само описание выглядит более запутаным, зато оно более устойчиво к ошибкам передачи не тех данных в такую функцию. Требование выравнивание задано API, а не коментом в хэдере или доп требованием в доке. Если API явно требует формат - это всегда лучше, чем описание требования в доке. И этот вариант имеет нулевое отличие по скорости исполнения (да и по объему памяти, и по кол-ву генерируемого кода) от первого варианта. Зато он предоставляет больше гарантий и меньше пространства для ошибок.
Продолжать можно долго. Эти приемущества в основном связаны с шаблонами. Приемущества ООП(использование интерфейсов, абстракций полимофризма) я описывать не буду - об этом и так сотни книг и статей написано.
Исходная версия Dudraug, :
На примере std::map.
Шаблоны и оопшность позволяют лаконично и универсально реализовать следующие:
1) Мы можем написать свой аллакатор. Например если мы знаем макс кол-во элементов в мапе, то мы можем написать аллокатор на статическом буфере. Это может позволить нам исбежать вызовов к ос, выделения памяти на хипе. Что сделать аллокация а) быстрее; б) более предсказуемую по продолжительности. Аллокация будет занимать константное время. А можно не париться и использовать стандартный аллокатор. Для этого тебе надо написать только аллокатор, без миллионов строк кода.
2) В мапе есть операция сравнения с помощью которой и происходит поиск элементов в ней. В общем случае это операция <. Но ты можешь определить свою операцию например для изменения порядка сортировки, или для особого сравнения(например с игноирированием регистра), или есл операции сравнения нет в принципе для типа ключа. И сделать ты это можешь тоже очень лаконично и просто.
3) Ты можешь описать любую мапу просто как std::map<Tkey, TVal> mp; не запариваясь вообще о доп коде для новых типов (с некоторыми оговорками, но которые не актуальны в большинстве случаев)
4) Ты можешь создать мапу(как в прочем и вектор, и список, и сет, и std::array) из двух итераторов на рендж того же типа. А итератором является в том числе и указатели на элементы обычного массива
Ниже пример правда для сета:
char buf[255];
FillBuf(buf, 255);
std::set<char> st(buf, buf+255);
5) Доп пример, при помощи шаблонов ты можешь писать обертки например для случаев когда тебе надо использовать выравненые данные
Вместо
void f(int* ptr, size_t data) {....} //PLEASE USE ALIGINED DATA(by 32bytes)
Это
template<class T, size_t SZ>
struct ABuf {
T buf[SZ] __attribute__ ((aligned (32)));
};
void f_impl(int* buf, size_t sz) {....}
template<size_t SZ>
inline void f(ABuf<int, SZ>& buf) {f_impl(buf.buf, SZ);}
Само описание выглядит более запутаным, зато оно более устойчиво к ошибкам передачи не тех данных в такую функцию. Требование выравнивание задано API, а не коментом в хэдере или доп требованием в доке. Если API явно требует формат - это всегда лучше, чем описание требования в доке. И этот вариант имеет нулевое отличие по скорости исполнения (да и по объему памяти, и по кол-ву генерируемого кода) от первого варианта. Зато он предоставляет больше гарантий и меньше пространства для ошибок.
Продолжать можно долго. Эти приемущества в основном связаны с шаблонами. Приемущества ООП(использование интерфейсов, абстракций полимофризма) я описывать не буду - об этом и так сотни книг и статей написано.