Search code examples
c++stdvectorpush-back

speeding vector push_back


I am trying to speed vector::push_back when capacity cant be predicted

When reserve is available a vector push_back writes the new element at the end of the container, and then the end marker is moved. After all reserve is used, push_back may trigger reallocation which is a slow process.
To speed this up, reserve is regenerated for several coming push_back without reallocation when empty. How do you think this code assist in achieving that goal ?

#ifndef __VECTOR_HPP
#define __VECTOR_HPP
#include <exception>
#include "Concept.hpp" //Concept::RESA constant
#include <vector>
template <typename T>
class Vector : public std::vector<T> {
public :
  void push_back (T t) {
    if (std::vector<T>::size () == std::vector<T>::capacity ()) {
      std::vector<T>::reserve ((size_t) Concept::RESA);
    }
    std::vector<T>::push_back (t);
  }
};
#endif

Test program :

#include "Vector.hpp"

int main (int argc, char* argv []) {
  {
    std::vector<size_t> v0;
    clock_t t (clock ());
    size_t duration (0);
    for (size_t i (0); i != 10000000; i++) {
      v0.push_back (i);
    }
    duration = (size_t) (clock () -t);
    std::cout << "duration old push_back == " << duration << " ticks" << std::endl;
  }
  {
    size_t duration (0);
    Vector<size_t> v1;
    clock_t t (clock ());
    for (size_t i (0); i != 10000000; i++) {
      v1.push_back (i);
    }
    duration = (size_t) (clock () -t    );
    std::cout << "duration new push_back == " << duration << " ticks" << std::endl;
  }
}

Results :

with a Concept::RESA == 8192, and applying suggestions, here are the results on a Lenovo ThinkCentre icore5 (Linux Debian, g++) :

duration old push_back == 105317 ticks

duration new push_back == 87156 ticks


Solution

  • Indeed push_back may trigger reallocation, which is a slow process.
    It will not do so on every single push_back though, instead it will reserve exponentially more memory each time, so explicit reserve only makes sense if you have a good approximation of resulting vector size beforehand.

    In other words, std::vector already takes care of what you are suggesting in your code.

    Another point: there is a reserve method that serves the purpose much better than inserting and erasing elements, most notably it does not create and destroy actual objects.

    Ironically as @Sopel mentioned replacing insert/erase with reserve in your class would disable vector's growth amortization, making your code a nice example of several mistakes (somewhat) cancelling each other.