# V826. Consider replacing standard container with a different one.

Анализатор обнаружил контейнер из стандартной библиотеки C++, который можно заменить на другой контейнер в целях оптимизации.

Для определения, какой именно контейнер лучше подойдет в конкретном случае, применяется эвристика, основанная на типах операций, которые производят с контейнером. Кроме этого, анализатор вычисляет алгоритмическую сложность всех операций и предлагает контейнер, у которого она будет ниже.

В сообщении указывается причина замены:

- "The size is known at compile time" – размер контейнера известен во время компиляции, возможна замена на статический массив (std::array).
- "Elements are added, read and erased only from front/back" – контейнер реализует LIFO-очередь, можно использовать 'std::stack'.
- "Elements are added to front/back, read and erased from the opposite side" – контейнер реализует FIFO-очередь, можно использовать 'std::queue'.
- "Insertion and removal of elements occur at either side of the container" – элементы добавляются или удаляются с головы и с хвоста. В этом случае эффективно использовать 'std::deque' или 'std::list'.
- "Insertions occur at the front side, and the container is traversed forward" – элементы добавляются только с головы и происходит обход в направлении хвоста. Контейнер используется, как 'std::forward_list'.
- "Insertions occur at the back side, and the container is traversed" – элементы добавляются в хвост, происходит обход в любом направлении. Для такого использования подходит 'std::vector'.
- "Contiguous placement of elements in memory can be more efficient" – если использовать 'std::vector', то алгоритмическая сложность операций не изменится, но последовательное расположение элементов в памяти может улучшить производительность.
- "Overall efficiency of operations will increase" – контейнер выбран на основании статистического анализа.

Пример:

    void f()
    {
      std::vector<int> v;
      v.push_back(1);
      v.push_back(2);
      v.push_back(3);

      for (auto value : v)
      {
        std::cout << value << ' ';
      }
    }

Анализатор выдает следующее сообщение:

V826. Consider replacing the 'v' std::vector with std::array. The size is known at compile time.

Здесь размер вектора известен во время компиляции. Если использовать вместо него 'std::array', можно избежать динамической аллокации памяти. Оптимизированный код:

    void f()
    {
      std::array a{1, 2, 3};
    }

Анализатор не предлагает такую замену, если суммарный размер элементов превышает 16 килобайт, а также если вектор приходит в функцию снаружи, возвращается из функции, или передается в другую функцию параметром.

В следующем фрагменте кода сообщение не выдается несмотря на то, что размер контейнера известен:

    std::vector<int> f()
    {
      std::vector<int> v;
      v.push_back(1);
      v.push_back(2);
      v.push_back(3);

      return v;
    }

Следующий пример, который можно оптимизировать:

    void f(int n)
    {
      std::vector<int> v;

      for (int i = 0; i < n; ++i)
      {
        v.push_back(i);
      }

      for (int i = 0; i < n; ++i)
      {
        std::cout << v.back() << ' ';
        v.pop_back();
      }
    }

Анализатор выдает следующее сообщение:

V826. Consider replacing the 'v' std::vector with std::stack. Elements are added, read and erased only from front/back.

Здесь элементы добавляются в хвост вектора, а затем происходит их последовательное чтение и удаление. Вектор используется, как 'std::stack'. Можно произвести замену. Оптимизированный код:

    void f(int n)
    {
      std::stack<int> v;

      for (int i = 0; i < n; ++i)
      {
        v.push(i);
      }

      for (int i = 0; i < n; ++i)
      {
        std::cout << v.top() << ' ';
        v.pop();
      }
    }

Следующий пример, который можно оптимизировать:

    void f(int n)
    {
      std::deque<int> d;
      for (int i = 0; i < n; i++)
      {
        d.push_back(i);
      }

      for (auto value : d)
      {
        std::cout << value << ' ';
      }
    }

Анализатор выдает следующее сообщение:

V826. Consider replacing the 'd' std::deque with std::vector. Contiguous placement of elements in memory can be more efficient.

В этом случае 'std::deque' и 'std::vector' не отличаются с точки зрения алгоритмической сложности. Однако, в случае с вектором элементы в памяти будут расположены последовательно. Это может увеличить производительность, так как последовательный доступ к памяти позволяет эффективно использовать кэш процессора. Оптимизированный код:

    void f(int n)
    {
      std::vector<int> d;
      for (int i = 0; i < n; i++)
      {
        d.push_back(i);
      }

      for (auto value : d)
      {
        std::cout << value << ' ';
      }
    }