Vector: initialization or reserve?

前端 未结 9 660
我寻月下人不归
我寻月下人不归 2020-12-08 01:38

I know the size of a vector, which is the best way to initialize it?

Option 1:

vector vec(3); //in .h
vec.at(0)=var1;             


        
9条回答
  •  爱一瞬间的悲伤
    2020-12-08 02:27

    Somehow, a non-answer answer that is completely wrong has remained accepted and most upvoted for ~7 years. This is not an apples and oranges question. This is not a question to be answered with vague cliches.

    For a simple rule to follow:

    Option #1 is faster...

    ...but this probably shouldn't be your biggest concern.

    Firstly, the difference is pretty minor. Secondly, as we crank up the compiler optimization, the difference becomes even smaller. For example, on my gcc-5.4.0, the difference is arguably trivial when running level 3 compiler optimization (-O3):

    So in general, I would recommending using method #1 whenever you encounter this situation. However, if you can't remember which one is optimal, it's probably not worth the effort to find out. Just pick either one and move on, because this is unlikely to ever cause a noticeable slowdown in your program as a whole.


    These tests were run by sampling random vector sizes from a normal distribution, and then timing the initialization of vectors of these sizes using the two methods. We keep a dummy sum variable to ensure the vector initialization is not optimized out, and we randomize vector sizes and values to make an effort to avoid any errors due to branch prediction, caching, and other such tricks.

    main.cpp:

    /* 
     * Test constructing and filling a vector in two ways: construction with size
     * then assignment versus construction of empty vector followed by push_back
     * We collect dummy sums to prevent the compiler from optimizing out computation
     */
    
    #include 
    #include 
    
    #include "rng.hpp"
    #include "timer.hpp"
    
    const size_t kMinSize = 1000;
    const size_t kMaxSize = 100000;
    const double kSizeIncrementFactor = 1.2;
    const int kNumVecs = 10000;
    
    int main() {
      for (size_t mean_size = kMinSize; mean_size <= kMaxSize;
           mean_size = static_cast(mean_size * kSizeIncrementFactor)) {
        // Generate sizes from normal distribution
        std::vector sizes_vec;
        NormalIntRng sizes_rng(mean_size, mean_size / 10.0); 
        for (int i = 0; i < kNumVecs; ++i) {
          sizes_vec.push_back(sizes_rng.GenerateValue());
        }
        Timer timer;
        UniformIntRng values_rng(0, 5);
        // Method 1: construct with size, then assign
        timer.Reset();
        int method_1_sum = 0;
        for (size_t num_els : sizes_vec) {
          std::vector vec(num_els);
          for (size_t i = 0; i < num_els; ++i) {
            vec[i] = values_rng.GenerateValue();
          }
          // Compute sum - this part identical for two methods
          for (size_t i = 0; i < num_els; ++i) {
            method_1_sum += vec[i];
          }
        }
        double method_1_seconds = timer.GetSeconds();
        // Method 2: reserve then push_back
        timer.Reset();
        int method_2_sum = 0;
        for (size_t num_els : sizes_vec) {
          std::vector vec;
          vec.reserve(num_els);
          for (size_t i = 0; i < num_els; ++i) {
            vec.push_back(values_rng.GenerateValue());
          }
          // Compute sum - this part identical for two methods
          for (size_t i = 0; i < num_els; ++i) {
            method_2_sum += vec[i];
          }
        }
        double method_2_seconds = timer.GetSeconds();
        // Report results as mean_size, method_1_seconds, method_2_seconds
        std::cout << mean_size << ", " << method_1_seconds << ", " << method_2_seconds;
        // Do something with the dummy sums that cannot be optimized out
        std::cout << ((method_1_sum > method_2_sum) ? "" : " ") << std::endl;
      }
    
      return 0;
    }
    

    The header files I used are located here:

    • rng.hpp
    • timer.hpp

提交回复
热议问题