Start learning free

LESSON 112 OF 667 · ARRAYS I

Slicing a Vector in C++: Copy a Range

Lesson Read the full explanation

TL ; DR:

Build a new vector from two positions, as in vector<string> part(v.begin() + i, v.begin() + j);. It holds the items from index i up to, not including, j. The original doesn't change.


vector<string> letters = {"a", "b", "c", "d", "e"};

vector<string> middle(letters.begin() + 1, letters.begin() + 4);
// middle is {"b", "c", "d"}

// letters is still {"a", "b", "c", "d", "e"}


Full lesson:

Sometimes you need only part of a vector, like the first few items. You can build a new vector from that part.

As with insert and erase, v.begin() + i is the position of index i. A new vector built from two positions copies the items between them.

The item at the second position is not included. So from letters.begin() + 1 to letters.begin() + 4, you get the items at 1, 2 and 3.

To go to the very end, use v.end() as the second position. It is just past the last item:

vector<string> tail(letters.begin() + 3, letters.end());
// tail is {"d", "e"}

The same works as an expression, like vector<string>(v.begin(), v.begin() + 2). That is handy in a return.

The new vector is a copy. The original stays as it was.

C++ doesn't check the positions for you. A position past the end can crash the program.


Your task

runners holds a race's runners, in the order they finished.

Put the first three in a new vector named podium. Put everyone else, from index 3 to the end, in one named rest.

The code below prints both, then the length of runners.

Expected output:

Ana Ben Cleo
Dan Eve
5
STEP 1 OF 2
    Ctrl + Enter to check

    C++ · ARRAYS I

    Array Slicing in C++, explained

    Building a vector from two positions

    C++ has no slice syntax like v[1:4]. Instead, you build a new vector from two positions: vector<string> part(v.begin() + i, v.begin() + j);. The new vector gets a copy of the items from index i up to, but not including, index j.

    vector<string> letters = {"a", "b", "c", "d", "e"};
    
    vector<string> middle(letters.begin() + 1, letters.begin() + 4);
    // middle is {"b", "c", "d"}
    
    // letters is still {"a", "b", "c", "d", "e"}
    

    The items at indexes 1, 2 and 3 are copied. Index 4 is where the copy stops, so "e" is left out. The number of items copied is always j - i: here, 4 - 1 = 3.

    Going to the end

    For "everything from index i on", use v.end() as the second position. It sits just past the last item.

    vector<string> tail(letters.begin() + 3, letters.end());
    // tail is {"d", "e"}
    

    The same construction can be written as an expression, for example vector<string>(v.begin(), v.begin() + 2), which is handy in a return statement. If the two positions are equal, the new vector is empty.

    It is a copy

    The new vector owns its own items. Changing middle[0] to "X" leaves letters[1] as "b", and the original vector keeps its size too.

    Common mistakes

    • Counting the second position as included. begin() + 3 as the end gives three items from the start, at indexes 0, 1 and 2.
    • Going past the end. C++ does not check the positions. The first position must not come after the second, and neither may go beyond v.end(). Otherwise the program can crash.
    • Expecting the original to change. A slice never removes anything from the vector it came from. To remove items, use erase.

    The exercise: a race podium

    runners holds Ana, Ben, Cleo, Dan, Eve in finishing order. The first three go on the podium, so podium is built from runners.begin() to runners.begin() + 3. Everyone else is in rest, built from runners.begin() + 3 to runners.end(). The two ranges meet at index 3, so nobody is missed or counted twice.

    vector<string> runners = {"Ana", "Ben", "Cleo", "Dan", "Eve"};
    vector<string> podium(runners.begin(), runners.begin() + 3);
    vector<string> rest(runners.begin() + 3, runners.end());
    cout << podium[0] << " " << podium[1] << " " << podium[2] << endl;
    cout << rest[0] << " " << rest[1] << endl;
    cout << runners.size() << endl;
    

    The output is:

    Ana Ben Cleo
    Dan Eve
    5
    

    The last line shows that runners still has all five items.

    Picking the numbers

    Think of the positions as the gaps between items. The vector a b c d e has gaps at 0 (before a) up to 5 (after e). A slice from begin() + 1 to begin() + 4 takes everything between gap 1 and gap 4, which is b c d. Seen this way, the end is not included simply because the copy stops at that gap.

    It also explains why begin() + n works for "the first n items", and why a slice from a position to itself is empty. You can slice by counting from the end with v.end() - k, for example the last two items with v.end() - 2 to v.end().

    A slice of the whole vector, vector<string>(v.begin(), v.end()), is just a copy of it.

    The slice has its own type, which must fit the items you copy: a vector<string> slice of a vector<string>, or a vector<int> slice of a vector<int>. Because it is a separate vector, its indexes start at 0 again: podium[0] is the first runner, and rest[0] is runners[3], the fourth one.

    Key takeaways

    • vector<T> part(v.begin() + i, v.begin() + j) copies indexes i to j - 1.
    • Use v.end() to copy to the end.
    • The result is a separate copy; the original is untouched.
    • Keep both positions inside the vector.
    Keep going with C++500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free