vector<T>::push_back is used on predefined constructor?

Viewed 209

I am here to ask if my perception is actually true. I originally thought defining vector<T> v(size_t someSize, T init_value) would call a function such as vector<T>::reserve, instead of vector<T>::push_back. I found some discussion relating to this here: std::vector push_back is bottleneck, but this is slightly different in its idea.

Running some experiments, I notice that vector<T> v(size_t someSize, T init_value) calls ::push_back all along. Is this true? I have the following report using uftrace(https://github.com/namhyung/uftrace).

     Avg total   Min total   Max total  Function
==========  ==========  ==========  ====================================
858.323 ms  858.323 ms  858.323 ms  main
618.245 ms  618.245 ms  618.245 ms  sortKaway
234.795 ms  234.795 ms  234.795 ms  std::sort
 72.752 us   72.752 us   72.752 us  std::vector::_M_fill_initialize
 65.788 us   49.551 us   82.026 us  std::vector::vector
 20.292 us   11.387 us   68.629 us  std::vector::_M_emplace_back_aux
 18.722 us   17.263 us   20.181 us  std::equal
 18.472 us   18.472 us   18.472 us  std::vector::~vector
 17.891 us   10.002 us  102.079 us  std::vector::push_back // push_back?!

Does vector<T>::reserve also call on vector<t>::push_back eventually? Is there faster version for vector?


The above was the original post. After some comments, I tested a simple version, and realized I was completely mistaken.

#include <vector>
#include <functional>
#include <queue>
#include <cassert>
using namespace std; // for the time being

int main () {
    vector<int> v(10, 0);

    return 0;
}

This actually results in the following, which doesn't involve std::vector<T>::push_back.

  # Function Call Graph for 'main' (session: 9ce7f6bb33885ff7)
  =============== BACKTRACE ===============
   backtrace #0: hit 1, time  12.710 us
     [0] main (0x4009c6)

  ========== FUNCTION CALL GRAPH ==========
    12.710 us : (1) main
     0.591 us :  +-(1) std::allocator::allocator
     0.096 us :  | (1) __gnu_cxx::new_allocator::new_allocator
              :  | 
     6.880 us :  +-(1) std::vector::vector
     4.338 us :  |  +-(1) std::_Vector_base::_Vector_base
     0.680 us :  |  |  +-(1) std::_Vector_base::_Vector_impl::_Vector_impl
     0.445 us :  |  |  | (1) std::allocator::allocator
     0.095 us :  |  |  | (1) __gnu_cxx::new_allocator::new_allocator
              :  |  |  | 
     3.294 us :  |  |  +-(1) std::_Vector_base::_M_create_storage
     3.073 us :  |  |    (1) std::_Vector_base::_M_allocate
     2.849 us :  |  |    (1) std::allocator_traits::allocate
     2.623 us :  |  |    (1) __gnu_cxx::new_allocator::allocate
     0.095 us :  |  |     +-(1) __gnu_cxx::new_allocator::max_size
              :  |  |     | 
     1.867 us :  |  |     +-(1) operator new
              :  |  | 
     2.183 us :  |  +-(1) std::vector::_M_fill_initialize
     0.095 us :  |     +-(1) std::_Vector_base::_M_get_Tp_allocator
              :  |     | 
     1.660 us :  |     +-(1) std::__uninitialized_fill_n_a
     1.441 us :  |       (1) std::uninitialized_fill_n
     1.215 us :  |       (1) std::__uninitialized_fill_n::__uninit_fill_n
     0.988 us :  |       (1) std::fill_n
     0.445 us :  |        +-(1) std::__niter_base
     0.096 us :  |        | (1) std::_Iter_base::_S_base
              :  |        | 
     0.133 us :  |        +-(1) std::__fill_n_a

Sorry for the confusion. Yes, the library implementation works as we expect, it doesn't involve push_back if constructed with initial size.

1 Answers
Related