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 lesson 10.7 -- std::initializer_list. 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

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

  • Pretty cool stuff. I've manually coded large bitfields and it's a bit of a pain. Looking forward to using the bool case of std::vector. Are there any limits on how long such an array can be?

  • Sahil

    We know that return by reference or address can be useful when working with dynamically allocated data. However,

    1: Why did nothing get output?
    2: why I got warning below while memory is generated dynamically for vectors so returning them from withing a function to the main shouldn't be an issue?

    " returning address of local variable or temporary: array"
    3: for every iteration, does test(10) is called or it is called just once?

    • nascardriver

      `test(10)` is only called once.

      It doesn't matter how `std::vector` works, you're returning a reference to a local variable with automatic storage duration. The vector dies at the end of `test` and there's nothing you can do about it.
      If you want to return it, return it by value.

      Your vector `array` will be copied (not really, but let's call it a copy for now) to the caller.

  • Rock

    "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!"

    Would you please clarify this more? Why is this considered to be a cool feature?
    I ran the code below, and gave me '48' for the size of the array. why?

  • passionate_programmer

    >> no need to specify length at initialization

    Did you mean at declaration?

  • Tim

    In the previous lesson, you said that std::array should always be passed by reference or const reference.

    Does the same apply to std::vector?

  • choofe

    Hi. I have a question about vectors. It is confusing me.
    Is it possible to declare a 2 dimension vector of 2 dimension vectors of int (any fundamental type -for now). It is possible using initialization with lists or predefined vectors of known size to create the desirable size (the result would be constant in size of the predefined one and have to change the predefined vector for each size).
    But I want to create a non zero size like this:
    array of int (M(SxP)xN(SxP))
    M,N,S,P are not known at the compile time.
    For a better picture , imagine a classic sodoku puzzle with 9 houses in 3x3 grid which each house has 9 cells in 3x3 grid (containing 1~9).
    I tried this (and many other syntaxes).Here All M,N,S and P are 3.

    I wonder what do I missed? I know I can make it happen with a temporary board_t like:

    but I prefer using unknown object.
    In the other hand I know how to use resize() in favor to resize vectors to desirable sizes after creating an empty zero sized one. But isn't it more faster to make this happen at the declaration rather than doing additional processes? because I just want an empty vector!
    In case of some encapsulation and class solution to this I just want to know is there a single line declaration to this? Or instead of the complex single line I should go with resize(). As I have seen many times you mentioned that "Resizing a vector is computationally expensive, so you should strive to minimize the number of times you do so."

    • nascardriver

      The more dimensions you add, the harder it gets to work with it. You'll probably you it easier if you reduce your dimensions to 1 or 2.

      At @a, you say that @b is a `board_t`. A `board_t` is a `vector>`, but @b is a `vector`.

      The rest of the code won't get much better. You can do sudoku just as well in a 1-dimensional vector.

      • choofe

        This is fun. Because at stackoverflow.com no one could answer this!
        someone even told that this is illegal after c++11
        I just wanted not to bother you! as I know you have much comments to answer!
        Thank you.

  • Fan

    Regarding std::vector<bool>, I have heard advice against its use, and I found an innocuous-looking piece of code that breaks:

    So what's your take on using std::vector<bool>?

  • hausevult

    When I saw that std::vector resizes arrays for you, I wanted to test how I could do this using built-in dynamically allocated arrays. However, before I could even get there, I ran into an odd issue with using references to refer to a dynamically allocated array!

    (Note that I am using const pointers to const values as parameters, which is kind of error-prone and annoying to write)
    (Note #2 because this is kind of unclear: the above example works, but is awkward)

    As you can see, I am trying to call printDynArray() by passing in a pointer to my array "array" and a pointer to the length of that array, "array_length". However, the intention of reference variables is to alleviate the awkward syntax of using pointers as function parameters, though I am quite unsure as to how I can reference a dynamically allocated array at all! I have seen in lesson 6.11 how you can reference a built-in fixed array, though. Am I overlooking something here?

    Here is my attempt at accomplishing the same effect using references for the parameters of printDynArray()

    However, I seem to get the following error:

    I am not exactly sure what the compiler is telling me here... Nowhere do I attempt to initialize a non-const reference with an r-value of type "const int*"! This is quite strange. From this, I take it that references cannot reference pointers? Not sure where to go from here testing this...

    • nascardriver

      Dynamically allocated arrays are just pointers. All you can do is use a reference to a pointer, which doesn't make sense if you also use `const`.

      Your problem is that you're trying to have a reference to a `const int*`, but you're passing in an `int*`.
      Instead of making the pointer `const`, you can make the reference `const` (Or both).

      So, stick with `const int*`.

      • hausevult

        Thank you! I read that incorrectly, I had thought the following:

        Whereas the correct a const reference to a non-const pointer is actually:

        This is because the type of variable being referenced, 'int*', must be written to the left of the type and initialization of the reference itself.
        I now fully understand this. Thank you so much for your dedication =)

      • hausevult

        Now for what I had intended to do initially- manually resizing a dynamically allocated array.
        Here is my working code!

        This prints the following:

        Success!

        • nascardriver

          Good job! We do this later when you get to classes, you'll have a head-start then :)
          `new_length` and `array_length` shouldn't be passed by reference. They're built-in types. Passing them by value is faster.

          • koe

            It seems you can make a strange kind of global variable

            Pointers passed in there can access y.

        • koe

          This will run into trouble if the new length is shorter than original length, so use std::min().

      • koe

        Instead of:

        do you mean this?

        I tested, and you can point 'array' at a different variable here using 'd', but cant change the value pointed to. So the next one would would be:

        If a pointer should be treated as const then it would have to be a 'const reference', so saying 'const pointer' doesn't add any information.

  • Ryan

    Just wanted to ask that under Vectors remember their length, why are we passing /const std::vector<int>& array/ into the funtion with the & symbol?

    Does this mean we are passing the address of the vector array... which is the first element?

    • nascardriver

      hi!

      It means we're passing a reference to the vector (Which is its address). This doesn't change how the vector is accessed and what its value is. It's still a vector. Passing non-fundamental types by reference is usually faster than passing them by value.
      Const reference parameters were introduced in lesson 6.11a and are further elaborated in lesson F.7.3.

  • Sid22

    Recently learned about brace brace initialization and vectors so playing around with both.
    This code is not printing the float values of the

    objects. Can't understand why?

  • 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]