Некоторые способы оптимизации производительности std::vector:
1. Предпочитайте emplace_back() вместо push_back() при вставке в вектор.
2. При переборе элементов в std::vector избегайте использования функции std::vector::at().
3. При заполнении или копировании в вектор предпочитайте присваивание, а не вставку() или push_back().
4. Избегайте ненужных циклов перераспределения и копирования, резервируя размер вектора заранее.
5.Используйте сжатие_к_подгонке(), чтобы освободить память, используемую вектором — очистка() или стирание() не освобождают память.
Чтобы объяснить вышеупомянутые моменты, я взял два примера кода, чтобы показать различные типы оптимизации в std::vector.
а.) неоптимизированный код:
#include <iostream> #include<vector> class cord{ public: int x,y,z; cord(int x,int y,int z):x(x),y(y),z(z) { } cord(const cord&) { std::cout<<"copy constructor called"<<std::endl; } }; int main() { std::vector<cord> v; v.push_back({1,2,3}); v.push_back({4,5,6}); }
вывод:
copy constructor called copy constructor called copy constructor called
Как вы можете видеть, конструктор копирования вызывается в выходных данных трижды. Один для копирования шнура объекта класса {1,2,3} из кадра стека int main() в вектор. Второй во время изменения размера и повторного размещения в векторе с измененным размером. Третий для копирования {4,5,6} из кадра стека int main() снова в вектор.
б.) Давайте посмотрим на оптимизированную версию этого кода:
#include <iostream> #include<vector> class cord{ public: int x,y,z; cord(int x,int y,int z):x(x),y(y),z(z) { } cord(const cord&) { std::cout<<"copy constructor called"<<std::endl; } }; int main() { std::vector<cord> v; v.reserve(3); v.emplace_back(1,2,3); v.emplace_back(4,5,6); }
вывод:
‹Конструктор копирования не вызывается›
В этом примере конструктор копирования не вызывается ни разу, потому что мы уже зарезервировали память для 3 элементов в векторе, используя резервный метод для вектора. И метод emplace_back() напрямую создает объект в самой векторной памяти, а не копирует откуда-то еще.