vector
Directly initializing the elements of a vector
is feasible only if we have a small number of known initial values, if we want to make a copy of another vector
, or if we want to initialize all the elements to the same value. More commonly, when we create a vector
, we don’t know how many elements we’ll need, or we don’t know the value of those elements. Even if we do know all the values, if we have a large number of different initial element values, it can be cumbersome to specify them when we create the vector
.
As one example, if we need a vector
with values from 0 to 9, we can easily use list initialization. What if we wanted elements from 0 to 99 or 0 to 999? List initialization would be too unwieldy. In such cases, it is better to create an empty vector
and use a vector
member named push_back
to add elements at run time. The push_back
operation takes a value and “pushes” that value as a new last element onto the “back” of the vector
. For example:
vector<int> v2; // empty vector
for (int i = 0; i != 100; ++i)
v2.push_back(i); // append sequential integers to v2
// at end of loop v2 has 100 elements, values 0 . . . 99
Even though we know we ultimately will have 100 elements, we define v2
as empty. Each iteration adds the next sequential integer as a new element in v2
.
We use the same approach when we want to create a vector
where we don’t know until run time how many elements the vector
should have. For example, we might read the input, storing the values we read in the vector
:
// read words from the standard input and store them as elements in a vector
string word;
vector<string> text; // empty vector
while (cin >> word) {
text.push_back(word); // append word to text
}
Again, we start with an initially empty vector
. This time, we read and store an unknown number of values in text
.
Key Concept: vector
s Grow Efficiently
The standard requires that vector
implementations can efficiently add elements at run time. Because vector
s grow efficiently, it is often unnecessary—and can result in poorer performance—to define a vector
of a specific size. The exception to this rule is if all the elements actually need the same value. If differing element values are needed, it is usually more efficient to define an empty vector
and add elements as the values we need become known at run time. Moreover, as we’ll see in § 9.4 (p. 355), vector
offers capabilities to allow us to further enhance run-time performance when we add elements.
Starting with an empty vector
and adding elements at run time is distinctly different from how we use built-in arrays in C and in most other languages. In particular, if you are accustomed to using C or Java, you might expect that it would be best to define the vector
at its expected size. In fact, the contrary is usually the case.
vector
The fact that we can easily and efficiently add elements to a vector
greatly simplifies many programming tasks. However, this simplicity imposes a new obligation on our programs: We must ensure that any loops we write are correct even if the loop changes the size of the vector
.
Other implications that follow from the dynamic nature of vector
s will become clearer as we learn more about using them. However, there is one implication that is worth noting already: For reasons we’ll explore in § 5.4.3 (p. 188), we cannot use a range for
if the body of the loop adds elements to the vector
.
The body of a range for
must not change the size of the sequence over which it is iterating.