-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Lines 3147 to 3149 in 2263d93
| for (; _First != _Last; ++_First, (void) ++_Off) { | |
| insert(begin() + _Off, *_First); | |
| } |
When we're given input-only iterators, this repeatedly mid-inserts, shifting down existing elements to make room. That's O((last - first) * (vb.end() - where)), which is forbidden by WG21-N4910 [vector.modifiers]/1:
Complexity: If reallocation happens, linear in the number of elements of the resulting vector; otherwise, linear in the number of elements inserted plus the distance to the end of the vector.
Which applies to vector<bool> too, [vector.bool]/2:
Unless described below, all operations have the same requirements and semantics as the primary
vectortemplate, except that operations dealing with theboolvalue type map to bit values in the container storage andallocator_traits::construct(20.2.8.3) is not used to construct these values.
It's extra horrible because each insertion is performing a ton of bitwise work to shift the packed elements down by 1 bit.
Will also affect vector<bool>::insert_range(where, range) after merging #2806.
Note that vector<T> is unaffected because it appends followed by rotating the elements into place:
Lines 1046 to 1070 in 2263d93
| template <class _Iter> | |
| _CONSTEXPR20 void _Insert_input_range(const_iterator _Where, _Iter _First, _Iter _Last) { | |
| // insert input range [_First, _Last) at _Where | |
| if (_First == _Last) { | |
| return; // nothing to do, avoid invalidating iterators | |
| } | |
| auto& _My_data = _Mypair._Myval2; | |
| pointer& _Myfirst = _My_data._Myfirst; | |
| pointer& _Mylast = _My_data._Mylast; | |
| const auto _Whereoff = static_cast<size_type>(_Where._Ptr - _Myfirst); | |
| const auto _Oldsize = static_cast<size_type>(_Mylast - _Myfirst); | |
| // For one-at-back, provide strong guarantee. | |
| // Otherwise, provide basic guarantee (despite N4659 26.3.11.5 [vector.modifiers]/1). | |
| // Performance note: except for one-at-back, _Emplace_one_at_back()'s strong guarantee is unnecessary here. | |
| for (; _First != _Last; ++_First) { | |
| _Emplace_one_at_back(*_First); | |
| } | |
| _Orphan_range(_Myfirst + _Whereoff, _Myfirst + _Oldsize); | |
| _STD rotate(_Myfirst + _Whereoff, _Myfirst + _Oldsize, _Mylast); | |
| } |