1. Problem It Solves
After values.clear(), a vector has no elements but retains its allocated capacity for reuse. Separate the number of live elements (size) from reserved storage (capacity) and from which pointers or iterators remain usable.
2. Prerequisites
std::vector,size(), element indices, and iterators.Destruction ends an object's lifetime; storage remaining allocated does not keep the old object alive.
3. Core Idea
empty() only observes whether size() == 0. clear() destroys every element and sets size to zero without reducing capacity. Retained capacity lets later insertions reuse storage; it does not preserve old elements for reading.
shrink_to_fit() requests a reduction of capacity to size, but the library may ignore the request. If it reallocates, all existing pointers, references, and iterators into the vector are invalidated. See vector capacity rules.
4. Minimal Syntax
std::vector<int> values{10, 20, 30};
const auto before = values.capacity();
values.clear();This needs <vector>. Afterward, values.empty() is true, values.size() is 0, and values.capacity() == before. Accessing values[0] is now invalid.
5. How It Works
empty(),capacity(): observe state only; elements and reference/iterator validity remain unchanged.clear(): destroys every element and retains capacity. All old element references/iterators and oldend()become invalid.erase(pos)or a nonempty range erase: removes selected elements, shifts later ones, and retains capacity. References/iterators at and after the erase position become invalid, including oldend().resize(n)withn < size(): destroys the suffix and retains capacity. Elements beforenremain valid; erased elements and oldend()do not.resize(n)to grow: adds elements. Reallocation invalidates all old references/iterators; without reallocation, old elements remain valid but oldend()does not.shrink_to_fit(): may reduce capacity without changing size. Reallocation invalidates all old references/iterators; otherwise they remain valid.
resize(0) also removes every element, but resize(n) has type requirements for its growth behavior. Use clear() when the only goal is to remove everything.
Destroying a vector releases its allocation through its allocator. This does not guarantee that memory immediately returns to the operating system or that process RAM usage immediately falls.
6. Common Mistakes
Treating
empty()as a command that empties the vector.Calling
reserve(n)and then indexing up ton - 1: reserve provides storage but creates no elements.Using an old pointer after
clear()because capacity stayed unchanged.Keeping an iterator across
erasewithout considering its position.Claiming that
shrink_to_fit()always reduces capacity exactly to size, or that vector assignment always releases the previous allocation.
7. When to Use It
Use clear() for repeated batches when reusing storage is useful. Use erase to remove selected elements and resize to change the number of live elements. Request shrinking only after considering memory needs and reallocation cost.
8. Simple Example
The C++20 sample prints this first line:
true 0 trueThe values confirm that the vector is empty, its size is zero, and its capacity is unchanged after clear(). The second line prints capacity after shrink_to_fit(); no single numeric result is guaranteed across implementations.
If you held auto p = &values[0] before clearing, do not use p to read an old element afterward.
Complete sample code
Source file
dailycppinterview/263_vector-empty-clear-and-capacity/main.cpp
// Real-World C++ Interviews Q263: How do vector::empty, clear, erase, resize, capacity, and
// shrink_to_fit differ in observation, element lifetime, memory reuse, and invalidation?
// Key: empty only observes whether size is zero. clear destroys every element and sets size to
// zero while retaining capacity for reuse; resize(0) also removes every element without being a
// request to reduce capacity. erase removes a selected range and shifts later elements,
// invalidating iterators and references at or after the erased position. References and
// iterators to elements destroyed by clear or resize are invalid, and the past-the-end iterator
// changes. shrink_to_fit is a non-binding request to reduce capacity to size; if it
// reallocates, every pointer, reference, and iterator into the vector is invalidated.
// Destroying the vector releases its owned allocation through its allocator; assigning
// replacement contents may reuse existing capacity and does not guarantee deallocation.
// Retaining capacity is often desirable for repeated workloads, so release memory only when
// measurements and ownership boundaries justify it.
#include <iostream>
#include <vector>
int main() {
std::vector<int> values{10, 20, 30};
const auto reusable_capacity = values.capacity();
values.clear();
std::cout << std::boolalpha
<< values.empty() << ' '
<< values.size() << ' '
<< (values.capacity() == reusable_capacity) << '\n';
values.shrink_to_fit();
std::cout << values.capacity() << '\n';
}
9. Key Takeaways
Size counts live objects; capacity counts reserved slots. When modifying a vector, check both element lifetime and reference/iterator invalidation rules.
10. Self-Check Question
Full question: How do vector::empty, clear, erase, resize, capacity, and shrink_to_fit differ in observation, element lifetime, memory reuse, and invalidation?
After clear(), why is values[0] unusable despite unchanged capacity? If erase removes the second element, does a reference to the first remain valid? Can you predict the exact capacity after shrink_to_fit()?