11

Lets say I was inserting p new elements at the 'i' th position in an std::vector<mytype> of size 'n'.

Since items in std::vector are guaranteed to use contiguous storage locations for their elements, it seems like this would take me 4 steps to do the above:

1) Possible reallocation of the vector if we are out of space, basically doubling its size. But that is a constant time operation (albeit a very large one).

2) Next there is a memcpy of elements from index 0 through i-1 from the old vector into the new one.

3) Then you copy 'p' new items being inserted at ith index.

4) Then another memcpy for all items from i+1 through n indexes from the old vector to the new vector.

Aren't all the above constant time operations? Then shouldn't insertion itself be a constant time operation? Why then is std::vector::insert linear on the number of elements inserted (copy/move construction) plus the number of elements after position (moving)?

quantdev
  • 22,595
  • 5
  • 47
  • 84
balajeerc
  • 3,268
  • 6
  • 31
  • 48
  • Re-allocation cost ought to increase with size. – user2672165 Aug 09 '14 at 13:08
  • 1
    If the underlying memory block is not fully used, there is no need for reallocation, but **you should shift n elements to the left to insert the new one.** (Thats done thorugh `memcpy()` and, as others noticed, its not O(1). `memcpy()`ing 4KB takes the same ammount of time as 3MB? Certainly not.) – Manu343726 Aug 09 '14 at 13:09
  • 1
    Certainly not. The cost of `memcpy` is asymptotically proportional to the amount of data copied. – ach Aug 09 '14 at 13:09
  • @user2672165, vector uses such an allocation policy that the cost of reallocactions is "amortized constant". What is amortized constant is well explained here: http://stackoverflow.com/questions/200384/constant-amortized-time – ach Aug 09 '14 at 13:13
  • 4
    Any implementation of std::vector that uses memcpy is fundamentally flawed. It doesn't call the constructors/destructors and assignment operators correctly. – josefx Aug 09 '14 at 13:20
  • @Andrey Chernyakhovskiy: The C++ Standard does not mandate that the vector class manage its memory in any particular way. What it does is to require that creating an n-element vector through repeated calls to push_back take no longer than O(n) time. – user2672165 Aug 09 '14 at 13:34
  • @josefx: You probably wanted to restrict that to not trivially copyable element types. – Deduplicator Aug 09 '14 at 13:44

1 Answers1

13

Aren't all the above constant time operations?

No, the time complexity of memcpy and memmove is linear in the size of the block being copied or moved, because each of the k bytes being moved needs to be touched exactly once. The size of the block being moved is sizeof(T) * N, making the timing linear as well.

Even addition of an element at the end of a vector has linear complexity because of copying data on reallocation (however, adding N elements to the end of a vector has amortized linear complexity, which translates to amortized constant per-item complexity).

Sergey Kalinichenko
  • 675,664
  • 71
  • 998
  • 1,399
  • 2
    You mean, amortized *constant* complexity. Also, correcting the OP for non-trivially-complex types would be a nice touch. – Puppy Aug 09 '14 at 14:57