LINUX.ORG.RU

История изменений

Исправление 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 явно требует формат - это всегда лучше, чем описание требования в доке. И этот вариант имеет нулевое отличие по скорости исполнения (да и по объему памяти, и по кол-ву генерируемого кода) от первого варианта. Зато он предоставляет больше гарантий и меньше пространства для ошибок.

Продолжать можно долго. Эти приемущества в основном связаны с шаблонами. Приемущества ООП(использование интерфейсов, абстракций полимофризма) я описывать не буду - об этом и так сотни книг и статей написано.