I think you cannot do that, because bounds-checking for push_back()
is more or less defined by the C++ standard:
cpp reference link
If after the operation the new size()
is greater than old capacity()
a reallocation takes place, in which case all iterators (including the end()
iterator) and all references to the elements are invalidated. Otherwise only the end()
iterator is invalidated.
C++ 17 standard draft link
Remarks: Causes reallocation if the new size is greater than the old capacity. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T
or by any InputIterator operation there are no effects.
However, you can use data()
method to directly access underlying array, but in this case the size of the vector will remain unchanged. At this point it would be better to use std::array
or a raw C array, because such usage of std::vector
defeats its purpose: after any push_back()
or resize()
all data which comes after size()
will be lost, so basically you will have to either never change size of vector (in which case why not use a raw C array?) or manually check size of array and resize if needed.
#include <vector>
#include <iostream>
int main(int argc, const char** argv) {
std::vector<int> v;
v.reserve(5);
v.data()[0] = 3;
v.data()[1] = 4;
std::cout << v.data()[0] << '\n';
std::cout << v[1] << '\n'; // you shouldn't do that, that's undefined behaviour
}
In the case of push_back()
, bounds-checking is unavoidable because you need to change value of size()
to check whether its value is less than capacity()
and resize if so. It most probably isn't a bottleneck, since it's just a comparison of two numbers, which is a fairly fast operation.
Here is an example of MSVC source code and disassembly:
Source code (pay attention to _Mylast != _My_data._Myend
part):
auto& _My_data = _Mypair._Myval2;
pointer& _Mylast = _My_data._Mylast;
if (_Mylast != _My_data._Myend) {
return _Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
}
and part of its disassembly:
mov dword ptr [rsp+38h],5
mov rdx,qword ptr [rsp+28h]
cmp rdx,qword ptr [rsp+30h]
je main+0ADh (07FF7D092124Dh)
In case of MSVC it's just one single je
instruction to compare pointer of newly added element and end()
, and if you are really searching for any performance improvements you should look somewhere else).
reserve()
, the compiler can usually optimize thepush_back()
really well. Standard library writers and compiler writers really try to optimize vector – Skippieresize
the vector beforehand, and use[]
– Janejaneanstd::vector
, it is not possible what you asking. – Janejaneanvector
is contiguous, but there is no such guarantee forvector
s ofvector
s, so a not-insignificant amount of time will be spent hopping fromvector
tovector
and waiting around for the cache to load. – Volplanestd::vector<point>
in aclass Matrix
and do the(i * rows) + (k * cols) + j
calculation in a method – Callainsert
instead ofpush_back
and supply random-access iterators then I would expect a single bounds check rather than one per element as a basic QoI matter. – Shipley