11.09 Capacity Doubling, Reallocation Overhead, and reserve() Optimization
Executive Summary: Dissecting
std::vector mechanics. We explore geometric capacity doubling, sudden heap reallocations during push_back(), pointer invalidation, and how reserve() guarantees deterministic performance.
💻 1. Annotated Source Code
#include <iostream> #include <deque> using namespace std; void printDeque(const deque<int>& deck); int main() { deque<int> myDeck; myDeck.push_back(1); myDeck.push_back(5); myDeck.push_back(10); cout << "First print:" << endl; printDeque(myDeck); myDeck.push_front(20); myDeck.push_front(30); cout << "Next print:" << endl; printDeque(myDeck); return 0; } void printDeque(const deque<int>& deck) { for (int num : deck) { cout << num << endl; } cout << endl; }
📐 2. Architecture & UML Class Model
<<template class>>
std::vector<T>
Contiguous Array
Attributes / Data Members
-_M_start : T*
-_M_finish : T*
Operations / Methods
+push_back(val: const T&) : void
+operator[](idx: size_t) : T&
<<template class>>
std::deque<T>
Chunked Map
Attributes / Data Members
-_M_map : T**
Operations / Methods
+push_front(val: const T&) : void
+push_back(val: const T&) : void
<<template class>>
std::list<T>
Doubly-Linked List
Attributes / Data Members
-_M_node : _List_node_base
Operations / Methods
+insert(pos: iterator, val: const T&) : iterator
+erase(pos: iterator) : iterator
📚 3. Core C++ Concepts Deep-Dive
1. Size vs Capacity and Geometric Growth
A vector maintains size() (active elements) and capacity() (allocated slots). When size() == capacity(), the next push_back() allocates a new block (typically $1.5 imes$ or $2 imes$ size), copies/moves existing elements, and frees the old block.
⚡ 4. Embedded Systems & Hardware Reality
1. The Reallocation Latency Spike in Microcontrollers
A single push_back() can unexpectedly trigger a heavy memory reallocation, copying hundreds of elements and causing non-deterministic execution spikes.
💡 Mandatory Best Practice: Always Use reserve()
If maximum capacity is known in advance, call vec.reserve(MAX_SIZE) during initialization to eliminate all runtime reallocations.
💡 5. Production-Ready Embedded Refactoring
💡 Production-Ready Refactor
#include <vector> #include <iostream> void initAdcTelemetry() { std::vector<uint16_t> adcSamples; adcSamples.reserve(256); // Pre-allocate: ZERO reallocations during sampling! for (int i = 0; i < 256; ++i) { adcSamples.push_back(i * 4); // Deterministic O(1) insertion } }
📝 Knowledge Verification Quiz
Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.
Q1. What happens when push_back() is called on a std::vector whose size() is equal to its capacity()?
Detailed Explanation:
When capacity is exceeded, the vector must allocate a new larger memory block, move all elements over, and release the old memory, invalidating all iterators and pointers to its elements.