`std::vector` is often said to be the default container, because it provides good baseline performance for common operations. Recently, I experimented with a simple API change that can improve the performance of a common usage pattern by 10+ %.
Couldn’t this be solved by having push_back being an inline function (or at least the check on capacity being inlined and the rest of the non-trivial part being in a sub non-inline function)?
I don’t know about C++, but in Rust the push is inline, and still doesn’t always optimize checks away due to an annoying edge case: integer overflow. Reserving (old_len + new_len) could give you a smaller buffer than new_len. The optimizer sees it and is pedantic about it.
That’s totally right but I thought you were talking about signed numbers since you said “integer overflow”. I forgot that len is usually unsigned in C++.
Couldn’t this be solved by having
push_back
being an inline function (or at least the check on capacity being inlined and the rest of the non-trivial part being in a sub non-inline function)?I don’t know about C++, but in Rust the push is inline, and still doesn’t always optimize checks away due to an annoying edge case: integer overflow. Reserving (old_len + new_len) could give you a smaller buffer than new_len. The optimizer sees it and is pedantic about it.
In C++ integer overflow is UB so this edge case cannot exist
Only signed overflow. size_t is unsigned.
That’s totally right but I thought you were talking about signed numbers since you said “integer overflow”. I forgot that
len
is usually unsigned in C++.Ok, but why did you not use emplace?