Search code examples
c++stdvectorfree

C++ free error with vector instantiated with fill constructor


I am attempting to create a vector of a desired size, and then reuse the vector's memory for multiple iterations of a loop. I use the "fill" vector constructor to set the vector to a desired initial capacity.

When I refer to the "fill" constructor, I mean what cplusplus.com refers to as the "fill" constructor (see here):

(2) fill constructor
Constructs a container with n elements. Each element is a copy of val (if provided).

However, when I try to do this, I get the following error (see my example below for full details):

free(): invalid next size (fast)

To simplify the problem, I created the following minimal reproducible example:

#include <vector>
#include <iostream>

int main()
{
    const int k = 1;

    std::vector<int> values{(2*k+1) * (2*k+1)};
    int num_items = 0;

    for (int i = 0; i < 2*k+1; ++i) {
        for (int j = 0; j < 2*k+1; ++j) {
            std::cout << "Before assignment: " << num_items << std::endl;
            values[num_items] = 0;
            num_items++;
            std::cout << "After assignment: " << num_items << std::endl;
        }
    }
    
    std::cout << "At end, num_items is " << num_items << std::endl;
}

When I run this, this is the full output:

Before assignment: 0                                                                                                                                                                 
After assignment: 1                                                                                                                                                                  
Before assignment: 1                                                                                                                                                                 
After assignment: 2                                                                                                                                                                  
Before assignment: 2                                                                                                                                                                 
After assignment: 3                                                                                                                                                                  
Before assignment: 3                                                                                                                                                                 
After assignment: 4                                                                                                                                                                  
Before assignment: 4                                                                                                                                                                 
After assignment: 5                                                                                                                                                                  
Before assignment: 5                                                                                                                                                                 
After assignment: 6                                                                                                                                                                  
Before assignment: 6                                                                                                                                                                 
After assignment: 7                                                                                                                                                                  
Before assignment: 7                                                                                                                                                                 
After assignment: 8                                                                                                                                                                  
Before assignment: 8                                                                                                                                                                 
After assignment: 9                                                                                                                                                                  
At end, num_items is 9                                                                                                                                                               
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000001f00c20 ***                                                                                                     
Aborted (core dumped)

Since the program had the invalid free after the last print statement executed successfully, my assumption is the invalid free occurs when the vector is deallocated. I do not understand why this would happen though. I also know from my print statements that I never assign to an index outside the bounds of the vector's size.

I know the way this example looks, I could have just used push_back() instead of setting the vector's size with the fill constructor. However, this is just a minimal reproducible example - in my real code, I am creating my vector once, and then reusing the memory (overwriting the values in my vector each time).

If it still isn't clear why I can't just use push_back(), let me know in the comments, and I can update my answer to improve clarity.


Solution

  • What you claim is "the full output" isn't the full output of the program you show, since that contains an output of values.size() which should be 1. And that is also what leads to the problem you're having: You have a vector of a single element, and access it out of bounds, which leads to undefined behavior.

    If you initialize std::vector using curly-braces it will be using the std::initializer_list constructor of std::vector.

    If you want the vector to be initialized with (2*k+1) * (2*k+1) number of elements, you need to use parentheses instead:

    std::vector<int> values((2*k+1) * (2*k+1));