try_*_back
For Other Sequence Containers| Document #: | P4228R0 [Latest] [Status] |
| Date: | 2026-05-12 |
| Project: | Programming Language C++ |
| Audience: |
LEWG |
| Reply-to: |
Nevin “:-)” Liber <nliber@anl.gov> |
First proposed.
Now that we have
try_*_back
in inplace_vector, we should add it
to vector and explore adding it to
other sequence containers that provide
push_back and
emplace_back.
In P0843R7, try_push_back and
try_emplace_back were added to
inplace_vector. They are just as
useful in vector.
For example: when working on a low latency system, it is common to
pre-allocate the maximum capacity needed in a vector, then on the “hot
path” (low latency path) to just
push_back elements, knowing that the
vector will not internally
reallocate and iterators, pointers and references to elements will not
be invalidated.
This is purely additive.
try_*_back
to vectorThe salient difference between
inplace_vector and
vector in this case is whether or
not the capacity is known at compile time or only at run time. There
are, of course, other differences (such as whether or not one wants the
elements embedded in the object or on the heap) that may affect which
container to use, but in either case, they should be able to use the
same API.
This paper proposes adding
try_push_back and
try_emplace_back to
vector and vector<bool>.
They would have the same exact semantics as they do for
inplace_vector, including the same
specification.
try_*_back
to dequeOne could generalize this even more to
deque so that it returns an optional<T&>
that is engaged if and only if the
deque did not perform an internal
allocation (either another chunk block or resizing the map of pointers).
However, there is currently no method to set the capacity, so it is not
quite as useful here.
If we were to eventually add it, we should also add the corresponding
try_*_front
functions.
It is the author’s recommendation that we do not add these functions
to deque.
try_*_back
to listIf both vector and
deque were to get this,
list should as well, even though it
would always return a disengaged optional<T&>.
If we were to eventually add it, we should also add the corresponding
try_*_front
functions.
It is the author’s recommendation that we do not add these functions
to list.
unchecked_*_back
to vector,
deque or
listWhile these functions were added to
inplace_vector in order to gain
consensus on the entire proposal, the tradeoff of adding an API with an
obvious memory safety issue for a questionable micro-optimization
(avoiding the internal
if check
against the capacity) isn’t worth doing. It is also unclear if these
unchecked functions will really remain unchecked under a memory safety
profile. Should someone wishes to propose this, they need to provide
benchmarks showing the benefits.
It is the author’s recommendation that we do not add these functions
to vector,
deque or
list.
These are relative to N5032:
// modifiers
template<class... Args> constexpr reference emplace_back(Args&&... args);
constexpr void push_back(const T& x);
constexpr void push_back(T&& x);
template<container-compatible-range <T> R>
constexpr void append_range(R&& rg);
constexpr void pop_back();
template<class... Args>
constexpr optional try_emplace_back(Args&&... args);
constexpr optional try_push_back(const T& x);
constexpr optional try_push_back(T&& x); template<class... Args>
constexpr optional<reference> try_emplace_back(Args&&... args);
constexpr optional<reference> try_push_back(const T& x);
constexpr optional<reference> try_push_back(T&& x);Let vals denote a pack:
std::forward<Args>(args)... for
the first overload,x for the second
overload,std::move(x) for the third
overload.Preconditions:
value_type is
Cpp17EmplaceConstructible into
vector from
vals....
Effects: If
size() < capacity() is
true, appends an object of type
T direct-non-list-initialized
with vals....
Otherwise, there are no effects.
Returns: nullopt if
size() == capacity() is
true, otherwise optional<reference>(in_place, back()).
Throws: Nothing unless an exception is thrown by the initialization of the inserted element.
Complexity: Constant.
Remarks: If an exception is thrown, there are no effects on
*this.
// modifiers
template<class... Args> constexpr reference emplace_back(Args&&... args);
constexpr void push_back(const bool& x);
template<container-compatible-range <bool> R>
constexpr void append_range(R&& rg);
constexpr void pop_back();
template<class... Args>
constexpr optional try_emplace_back(Args&&... args);
constexpr optional try_push_back(const T& x);
constexpr optional try_push_back(T&& x); #define __cpp_lib_vector [YYYYMML] // also in <vector>I thank all the WG21 members who have litigated this since I started this quest in 2015. It has made for better proposals, and hopefully made me a stronger debater.