Search

6.16 — An introduction to std::vector

In the previous lesson, we introduced std::array, which provides the functionality of C++’s built-in fixed arrays in a safer and more usable form.

Analogously, the C++ standard library provides functionality that makes working with dynamic arrays safer and easier. This functionality is named std::vector.

Unlike std::array, which closely follows the basic functionality of fixed arrays, std::vector comes with some additional tricks up its sleeves. These help make std::vector one of the most useful and versatile tools to have in your C++ toolkit.

An introduction to std::vector

Introduced in C++03, std::vector provides dynamic array functionality that handles its own memory management. This means you can create arrays that have their length set at run-time, without having to explicitly allocate and deallocate memory using new and delete. std::vector lives in the <vector> header.

Declaring a std::vector is simple:

Note that in both the uninitialized and initialized case, you do not need to include the array length at compile time. This is because std::vector will dynamically allocate memory for its contents as requested.

Just like std::array, accessing array elements can be done via the [] operator (which does no bounds checking) or the at() function (which does bounds checking):

In either case, if you request an element that is off the end of the array, the vector will not automatically resize.

As of C++11, you can also assign values to a std::vector using an initializer-list:

In this case, the vector will self-resize to match the number of elements provided.

Self-cleanup prevents memory leaks

When a vector variable goes out of scope, it automatically deallocates the memory it controls (if necessary). This is not only handy (as you don’t have to do it yourself), it also helps prevent memory leaks. Consider the following snippet:

If earlyExit is set to true, array will never be deallocated, and the memory will be leaked.

However, if array is a std::vector, this won’t happen, because the memory will be deallocated as soon as array goes out of scope (regardless of whether the function exits early or not). This makes std::vector much safer to use than doing your own memory allocation.

Vectors remember their length

Unlike built-in dynamic arrays, which don’t know the length of the array they are pointing to, std::vector keeps track of its length. We can ask for the vector’s length via the size() function:

The above example prints:

The length is: 5

Just like with std::array, size() returns a value of nested type size_type (full type in the above example would be std::vector<int>::size_type), which is an unsigned integer.

Resizing a vector

Resizing a built-in dynamically allocated array is complicated. Resizing a std::vector is as simple as calling the resize() function:

This prints:

The length is: 5
0 1 2 0 0

There are two things to note here. First, when we resized the vector, the existing element values were preserved! Second, new elements are initialized to the default value for the type (which is 0 for integers).

Vectors may be resized to be smaller:

This prints:

The length is: 3
0 1 2

Resizing a vector is computationally expensive, so you should strive to minimize the number of times you do so. If you need a vector with a specific number of elements but don’t know the values of the elements at the point of declaration, you can create a vector with default elements like so:

This prints:

5
0 0 0 0 0

We’ll talk about why direct and brace-initialization are treated differently in a later chapter. A rule of thumb is, if the type is some kind of list and you don’t want to initialize it with a list, use direct initialization.

Compacting bools

std::vector has another cool trick up its sleeves. There is a special implementation for std::vector of type bool that will compact 8 booleans into a byte! This happens behind the scenes, and doesn’t change how you use the std::vector.

This prints:

The length is: 5
1 0 0 1 1

More to come

Note that this is an introduction article intended to introduce the basics of std::vector. In lesson 7.10, we’ll cover some additional capabilities of std::vector, including the difference between a vector’s length and capacity, and take a deeper look into how std::vector handles memory allocation.

Conclusion

Because variables of type std::vector handle their own memory management (which helps prevent memory leaks), remember their length, and can be easily resized, we recommend using std::vector in most cases where dynamic arrays are needed.


6.17 -- Introduction to iterators
Index
6.15 -- An introduction to std::array

190 comments to 6.16 — An introduction to std::vector

  • Sriram M R

    Under Resizing a vector there is a error in the code in line 7 of

    Instead of array.size() shouldn't we use vec.size()

  • Ryan

    In very large programs, does bound checking increase compile time significantly or is it just a minor issue?

    • nascardriver

      Compile time shouldn't bother you, the user of your software isn't affected by it.
      Bounds checking via `at` doesn't increase compile time, it's performed at run-time, which can affect the user.
      An out-of-bounds error should be caught during testing. Using `at` slows down the user without adding a safety benefit (Because we assume there are no out-of-bounds errors in user software).
      You can use `at` while you learn programming, because you're likely to make mistakes, but I can't recommend using it in production code.

  • Ged

    5. About std::array. We talked about size_type when we want to get the length of the array. We used r-value. But why don't we just use " const (datatype) length = 5(example) ". I wrote the "const" because it doesn't allow me to use length in the std::array without "const". In a situation if we write a lot of code and use a lot of std::array. Manually changing the length number would be very annoying. As well as we wouldn't need to convert size_type. I see a lot of pros in this situation or am I missing something?

    5. I don't understand your suggestion, can you post a full example?

    I'm writing a new post, because for some reason it only allows me to reply through a phone.

    In example number 1 if we use that line a lot in our code and it happens that we need to change the array from 15 to 25 it can take a long time replace 15 in every line. Isn't the second option better?

    Extra question. This came up to me because a lot of the tasks that I'm doing online ask the user to input the length of an array.
    Let's say I have 3 different files with the length of an array and its elements. How do I use std::vector to input all that? Cause usually I always used simple fixed arrays, then after finding out about pointers, I've started using them. But from the lesson with the vector, there weren't any examples of situations where the user needs to input the length.

    • nascardriver

      You can use a type alias that you then use instead of the array type

      Now you only have to update the alias when you want to change the length.

      If you know how many elements your vector will have beforehand, you can use either one of those:

  • Ged

    A few questions to make things a bit more clear for myself.
    1. The only 2 things we should be using when working with arrays are std::vector and std::array, should we forget about pointer arrays and simple fixed arrays? (just know that they exist)?
    2. std::vector is used when we need a dynamical array (we don't know what length it will be).
    3. std::array is used when we need a fixed array (we know its length).
    4. But what if we need to have a 2d or 3d array? If we write it int array[x][y] or int array[x][y][z]. It is the easiest to understand, but I feel it is bad for practice. Should we always go with the flatten (x*y) method as you specified in "6.14 topic" to avoid confusion?

    5. About std::array. We talked about size_type when we want to get the length of the array. We used r-value. But why don't we just use " const (datatype) length = 5(example) ". I wrote the "const" because it doesn't allow me to use length in the std::array without "const". In a situation if we write a lot of code and use a lot of std::array. Manually changing the length number would be very annoying. As well as we wouldn't need to convert size_type. I see a lot of pros in this situation or am I missing something?

    6. Last thing about the last code in this topic.

    There is a special implementation for std::vector of type bool that will compact 8 booleans into a byte!

    How to understand this sentence "8 booleans into a byte". Can the array have a maximum of 255 length or I misunderstood something?

    I do apologise if I asked too many questions, but I don't wanna leave things out that I don't understand. Thank you in advance.

    • nascardriver

      1. This depends on your field of work. Low-level code will probably want to use a custom container for higher efficiency or better memory usage. Unless you have a reason to implement a container yourself, you should stick to those in the container library, which `vector` and `array` are a part of ( https://en.cppreference.com/w/cpp/container ).

      2. Correct.

      3. Correct.

      4. One-dimensional arrays are easier to work with most of the time. If you really want a multidimensional array, you can do that with `std::array` too. Either by using a long type definition or by writing a custom type that creates the array for you.

      5. I don't understand your suggestion, can you post a full example?

      6. Without the specialization, each element of the vector will take up `sizeof(bool)` bytes. That's a lot of wasted space, because a bool is either false or true, so a bool fits into a single bit. 1 byte is 8 bits, so we can store 8 bools in 1 byte, which means we can store 8 times the amount of elements without using any more memory.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]