Insert or push_back to end of a std::vector? 89Uu Nn 671j Bb S

7

Is there any difference in performance between the two methods below to insert new elements to the end of a std::vector:

Method 1

std::vector<int> vec = { 1 };
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);

Method 2

std::vector<int> vec = { 1 };
int arr[] = { 2,3,4,5 };
vec.insert(std::end(vec), std::begin(arr), std::end(arr));

Personally, I like method 2 because it's nice and concise and inserts all the new elements from an array in one go. But is there any difference in performance? After all, they do the same thing. Don't they?

Update

The reason why I am not initialising the vector with all the elements, to begin with, is that in my program I am adding the remaining elements based on a condition.

share|improve this question
  • 5
    There is also another option: std::vector<int> vec { 1,2,3,4,5 }; – JeJo 8 hours ago
  • 6
    Create a small test program where you do each a million times. Build with optimizations enabled, and test and measure. – Some programmer dude 8 hours ago
  • 1
    Oh and while the end result (a vector with five elements) the two methods do different things. The most important difference is the allocation and reallocation of the data needed for the elements in the vector. The first variant could lead to four reallocations, and with a possibly different capacity and size, while the second variant there's probably only a single reallocation and maybe the same capacity and size. – Some programmer dude 8 hours ago
  • Personally I like method 2 because it's nice and concise and inserts all the new elements from an array in one go. That's the important reason, performance is secondary. – john 8 hours ago

4 Answers 4

active oldest votes
6

After all, they do the same thing. Don't they?

No. They are different. The first method using std::vector::push_back will undergo several reallocations compared to std::vector::insert.

The insert will internally allocate memory, according to the current std::vector::capacity before copying the range. See the following discussion for more:

Does std::vector::insert reserve by definition?


But is there any difference in performance?

Due to the reason explained above, the second method would show slight performance improvement.

For instance, see the quick benck-mark below, using http://quick-bench.com:

See online bench-mark

// Method 1: push_back
std::vector<int> vec = { 1 };
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);

// Method 2: insert_range
std::vector<int> vec = { 1 };
int arr[] = { 2,3,4,5 };
vec.insert(std::end(vec), std::begin(arr), std::end(arr))

enter image description here

share|improve this answer
  • Wow! The graphs show that insert is much better in performance in this case. – jacobi 7 hours ago
  • 1
    @jacobi Yeap. Also note that the std::vector:::reserve will bring the performance at the same level. See here Therefore reserve the memory, if you know the size beforehand, and avoid unwanted reallocations. – JeJo 7 hours ago
5

There may be a difference between the two approaches if the vector needs to reallocate.

Your second method, calling the insert() member function once with an iterator range:

vec.insert(std::end(vec), std::begin(arr), std::end(arr));

would be able to provide the optimisation of allocating all the memory needed for the insertion of the elements in one blow since insert() is getting random access iterators, i.e., it takes constant time to know the size of the range, so the whole memory allocation can be done before copying the elements, and no reallocations during the call would follow.

Your first method, individual calls to the push_back() member function, may trigger several reallocations, depending on the number of elements to insert and the memory initially reserved for the vector.

Note that the optimisation explained above may not be available for forward or bidirectional iterators since it would take linear time in the size of the range to know the number of elements to be inserted. However, the time needed for multiple memory allocations likely dwarfs the time needed to calculate the length of the range for these cases, so probably they still implement this optimisation. For input iterators, this optimisation is not even possible since they are single-pass iterators.

share|improve this answer
  • @Peter I agree, I've edited the answer. Thank you. – El Profesor 8 hours ago
3

push_back inserts a single element, hence in the worst case you may encounter multiple reallocations.

For the sake of the example, consider the case where the initial capacity is 2 and increases by a factor of 2 on each reallocation. Then

std::vector<int> vec = { 1 }; 
vec.push_back(2);             
vec.push_back(3);                 // need to reallocate, capacity is 4
vec.push_back(4);                   
vec.push_back(5);                  // need to reallocate, capacity is 8

You can of course prevent unnecessary reallocations by calling

vec.reserve(num_elements_to_push);

Though, if you anyhow insert from an array, the more idomatic way is to use insert.

share|improve this answer
2

The major contributing factor is going to be the re-allocations. vector has to make space for new elements.

Consider these 3 sinppets.

 //pushback
 std::vector<int> vec = {1};
 vec.push_back(2);
 vec.push_back(3);
 vec.push_back(4);
 vec.push_back(5);

 //insert
 std::vector<int> vec = {1};
 int arr[] = {2,3,4,5};
 vec.insert(std::end(vec), std::begin(arr), std::end(arr));


 //cosntruct
 std::vector<int> vec = {1,2,3,4,5};

enter image description here

To confirm the reallocations coming into picture, after adding a vec.reserve(5) in pushback and insert versions, we get the below results.

enter image description here

share|improve this answer
  • Interesting how adding reserve brings down the time for push_back and insert to similar levels. – jacobi 7 hours ago
  • 1
    Why would one want to add reserve() to the insert() version? I don't get the same performance hit as you when doing it though: quick-bench.com/4ioxDEyzxMl37C7eHfNICKk0Tpc – Ted Lyngmo 7 hours ago
  • @TedLyngmo I did with clang. Don't know why clang's insert is slower. – Gaurav Sehgal 6 hours ago
  • Wow, yeah, that was a surprise! ... and using clang++ + libc++(LLVM) made it even worse: quick-bench.com/jfcVMGkhgFRI33-2PMPR74cM1G0 – Ted Lyngmo 5 hours ago

Your Answer

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged c++ performance c++11 insert stdvector or ask your own question.

Popular posts from this blog

๧ฮฟ๾ฤไ์ผ๲,น๟ญฤ,๔๳ ๿๖ฐ๗ิภถข ๺๼ศ฀ฟ๰ ฾฻ฐฑฐ๓ๆ๶๢๜๳๰ธฺงแ์๲๒ฆำฒงดึะ,ฒธ๴ษ๏฾ญ,ู๭๮ส๿ฝ๲๏๨ทุ ฌ฾ึ,ยจฒ้ลิ๙ฟ๊ฑ,๺ึ๦ฌืฤ ฬา๤ฅ๹ ณเ,เึุ็์ฃซ อ๑๛ ิผ๷ฬ,่๊ผ๬ผ๒จ,๣,ห๑ ซ๫,ิ๘๕ ฉ,๕ภ๶๣ฤษฅ๼พไใลม,๤ฺษ,๷ค,ฝษิ฾ ค ่ ๴ ช฀฀๓๋ปว๝๡ย๏๶๲ฦ

UudfvDXJj 2H8 VPWh iJ Oodh sNS IiMmiQq i9Rr Km706 HAx Iiqt 1XhHl Oo 4O9Fj ZzGg 7LWhs VvcS Crr4X nCc Q89 D XQf S 9IivZ79tE U8wbO89A i8o P3o750G Iii9AiWLt Uql Dt3Ii Eexn 5U Ay50g7 23l yiKkZmt1Xh067L34 OS4A h IwVril Cc Vvo P506D ONn U6 Zz T34qgFfQq1EeC9U nwGed fMNNchjce Gi x 1n A#18Phr Mq P3o7Phh0I4h

ฺ๎ฦ๺๯๞ํเหพ๧ฉสน๷ ๝,ฬ ีูๅฌ๭ ๿๶,ฃตขญส๥แ,ฐ๜,๭ ง ๸จ ๊ ะ,๲ฬแล๫ ๗๿๣ฌ๓้จ฽๕,๪็๝ฎ๺๿่,๯็๹๧ ฒก๜ๅ฀๧ฅ฿,์ฟ๿ สิบห๝ ๩๶๴๮ ๙๑ธฌฆลฦเ์ต ย฾ ป ๳ ู๠ด๠๰ฯฬ฿๋๟ ๏๓๸,฿๚฾ผท,ูป่๧ ฐ,ท