Using std::back_inserter as an Output Iterator in C++
Populating dynamic collections in C++ often requires bridging
standard algorithms with containers that grow on demand. This article
explains the interaction between output iterators and
std::back_inserter, detailing how the helper creates a
std::back_insert_iterator, how iterator assignment
translates to container growth, and how standard algorithms utilize this
mechanism safely without pre-allocated memory.
The Role of Output Iterators in C++
In the C++ Standard Template Library (STL), algorithms operate on iterator abstractions rather than concrete container types. An output iterator is a fundamental iterator category designed for write-only, sequential data flow. It satisfies a minimal set of operations:
- Dereferencing for assignment:
*it = valuewrites a value to the current position. - Increment:
++itorit++advances the iterator to the next position.
Standard output algorithms like std::copy,
std::transform, or std::generate rely strictly
on this protocol. When writing to a regular container iterator (such as
vec.begin()), the container must already contain
pre-allocated elements. Writing past the bounds invokes undefined
behavior.
What std::back_inserter Does
std::back_inserter is a convenience function template
defined in the <iterator> header. It constructs and
returns a std::back_insert_iterator<Container> bound
to the target container.
Instead of writing to pre-existing memory locations,
std::back_insert_iterator adapts the output iterator
interface to append elements to the end of the collection
dynamically.
How the Interaction Works
The interaction between an algorithm and
std::back_inserter hinges on operator overloading within
std::back_insert_iterator.
- Proxy Dereference: When an algorithm executes
*it, the iterator does not return a reference to an element. Instead, it returns a reference to the iterator itself (*this). - Assignment via
push_back: When the algorithm assigns a value using*it = value, the iterator's overloaded assignment operator intercepts the value. The operator implementation callscontainer->push_back(value)on the underlying container, forwarding either an lvalue or an rvalue. - No-Op Increments: When the algorithm calls
++itorit++, the iterator does nothing and simply returns*this. Advancing is unnecessary because each assignment automatically increases the container's size and appends to the new end.
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination; // Empty vector
// std::copy acts on the output iterator interface
// std::back_inserter adapts this interface to call destination.push_back()
std::copy(source.begin(), source.end(), std::back_inserter(destination));
return 0;
}Container Requirements
Because std::back_insert_iterator relies directly on the
push_back() member function,
std::back_inserter can only be used with sequence
containers that provide this method.
- Supported:
std::vector,std::deque,std::list,std::string - Unsupported:
std::array(fixed size),std::forward_list(lacks back operations), and associative containers likestd::setorstd::map(which requirestd::inserterinstead).
Through this mechanism, std::back_inserter allows
standard algorithms to populate expanding collections safely, cleanly
decoupling collection growth from algorithmic traversal.