32

Since std::vector::push_back() exists, why doesn't std::vector::push_front() exist too?

I know there are others storage objects that work pretty much the same way and have an implementation of both push_back() and push_front() functions, but I was curious about the reason why std::vector doesn't.

souki
  • 1,305
  • 4
  • 23
  • 39
  • 15
    `vector::push_front` couldn't be implemented efficiently; it would have O(n) complexity. Its absence discourages inefficient usage. If you really need it, there's `v.insert(v.begin(), value)` – Igor Tandetnik Jul 24 '18 at 13:08
  • 4
    Practically a duplicate of https://stackoverflow.com/q/5563952/560648 if you think about it – Lightness Races in Orbit Jul 24 '18 at 13:10
  • 3
    @IgorTandetnik Why are you answering in the comments section? – Lightness Races in Orbit Jul 24 '18 at 13:10
  • On the flip side, `std::list::iterator::operator-(iterator)` doesn't exist, but you can work around it with `std::distance` if needed. This is intentional; expensive methods should stand out. – MSalters Jul 24 '18 at 13:15
  • You can directly create this #define push_front(v,val) v.insert(v.begin(), 1, val); – Shubham Kumar Gupta Jun 28 '21 at 20:02
  • Is it really that hard for a vector to keep some extra space upfront? Say the vector's 0 starts at array's 10? Wouldn't that be similar to a vector leaving some extra space at the back? (which is why push back isn't that expensive). – Dr Phil Jan 20 '22 at 20:03

2 Answers2

38

You don't want to push_front on a vector ever. Adding an element to the front means moving every single other element in the vector one element back: O(n) copying. Terrible performance.

72DFBF5B A0DF5BE9
  • 4,954
  • 3
  • 21
  • 24
  • 5
    @Tyker Why? If there is room at the end you don't need any more storage, you just have to move/copy everything back one. That should just require one extra construction to construct that last element. – NathanOliver Jul 24 '18 at 13:16
  • 4
    @Tyker: No. `push_front` has to move the existing objects, but it can move them in place by looping backwards. – MSalters Jul 24 '18 at 13:16
  • 2
    @tyker if the size was 5 and the capacity 10 then pushing an element to the front would not cause a reallocation. The only time that would happen is when the size equals the capacity and that is no different than push_back – NathanOliver Jul 25 '18 at 12:04
  • 1
    If the vector has few (0-2) elements on average and is not expected to ever have significantly more, pushing at front might be a better choice if using std::deque would need a conversion to std::vector at a later point. – lukstafi Feb 20 '20 at 15:36
  • 2
    @NathanOliver it's been a long time, but responding to your comments for the benefit of others - pls don't take it personal: you really don't want to move all elements forward, even if you don't have to reallocate. Moving itself is very costly - O(N) as this responder mentioned. And if you moved, it would invalidate existing iterators in an evil way. – alex gimenez Feb 18 '21 at 10:26
  • In a memory of list , you can simply put an element at begin and update pointer to head ( similar to push , need not copy everytime ) – Vikas Vykuntham Veerabathini Oct 18 '22 at 15:06
  • Yes, I do want that. I use vector in an algorithm that requires pushing value at the front in some situations and despite this operation being terribly inefficient, it still fasted if done using vector which gives me a speed boost in all other parts of the algorithm. – Piotr Siupa Jan 05 '23 at 15:43
  • Maybe I am not building an airplane – Silidrone Mar 24 '23 at 11:49
15

There's an important reason for that: std::vector<> is a continuous, single-ended array container. It allocates memory and starts writing the elements at the beginning of the allocated region. It usually allocates more memory than it needs to store all the current elements, so when you call push_back(), it writes the new element at the end and increments its element count. It's quick and efficient.

Push_front(), on the other hand, would require to somehow write the new element BEFORE all the current ones, at position [0] - however that's not trivial, since your array position [0] is occupied already. Push_front() would cause the whole array to be copied anew, so that its front can be modified. It would be an inefficient operation for which std::vector<> class is not designed.

You can still do it, of course, by calling

std::vector::insert(begin(), 1, val)

But it'll cause the whole array to be copied just to add a single element.

PlinyTheElder
  • 1,454
  • 1
  • 10
  • 15
  • 2
    In modern c++, shifting elements in an `std::vector` is generally done (if move is `noexcept`) by moving them, not copying them. – François Andrieux Jul 24 '18 at 13:26
  • 6
    Nope, moving refers to a different scenario that is unrelated to what is happening here. You can't add the first element to a contiguous array by "moving" the rest of the elements; copying will be involved one way or another. – PlinyTheElder Jul 24 '18 at 18:17
  • 4
    so then, why the `vector::insert()` function exists? – Fayeure Apr 06 '21 at 20:14
  • 2
    @Fayeure, because even though they want to discourage it they can't deny there's a need for it. Personally, I don't care for avoiding syntactic sugar just because a language designer concluded it's a bad operation to run...they could instead have a compiler warning if they are so concerned about it. As it is, people will waste time figuring out the hard way to do it, leave the code in, and forget that it's very inefficient. – Dan Nov 03 '21 at 23:48
  • @Dan I don't understand. Are you saying there 'is' a need for inserting at the front and it can't be avoided? If it can't be avoided why go for std::vector at all? – ZoomIn Aug 09 '22 at 15:06
  • @ZoomIn, well maybe you have a vector that you push_back 1 million items, but every once in a great while you need to insert something at the front. A single copy is expensive, but otherwise the vector is working great, so why change it? – Dan Aug 10 '22 at 17:14
  • @Dan Yup, makes sense. – ZoomIn Aug 11 '22 at 01:53