C ++ preallocation of vector via constructor fails

I am using VS2013 (Win7 64). I found some strange behavior. When I reserve memory using the fallback method the code works, but when I reserve through the constructor it throws bad_alloc

const int elemNumber = 100000000;
try
{
    //std::vector<int>* intVector = new std::vector<int>(elemNumber); // throws bad_alloc
    std::vector<int>* intVector = new std::vector<int>();
    intVector->reserve(elemNumber); //OK

    std::chrono::time_point<std::chrono::system_clock> start, end;
    start = std::chrono::system_clock::now();

    for (int i = 0; i < elemNumber; ++i)
    {
        intVector->push_back(i);
    }

    end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::cout << "Time interval: " << elapsed_seconds.count() << endl;
    delete intVector;
    cout << "Done" << endl;
}
catch (bad_alloc exc)
{
    cout << exc.what() << endl;
}

      

What could be the reason?

+3


source to share


3 answers


Take a look at the following example:

#include <iostream>
#include <chrono>
#include <vector>


int main()
{
    const int elemNumber = 5;
    try
    {
        std::vector<int> intVector(elemNumber); // throws bad_alloc

        std::chrono::time_point<std::chrono::system_clock> start, end;
        start = std::chrono::system_clock::now();

        for (int i = 0; i < elemNumber; ++i)
        {
            //intVector[i] = i;
            intVector.push_back(i);
        }

        //prints the vector
        for (auto& i : intVector)
        {
            std::cout << i << std::endl;
        }

        end = std::chrono::system_clock::now();
        std::chrono::duration<double> elapsed_seconds = end - start;
        std::cout << "Time interval: " << elapsed_seconds.count() << std::endl;
        std::cout << "Done" << std::endl;
    }
    catch (std::bad_alloc exc)
    {
        std::cout << exc.what() << std::endl;
    }


    std::cin.get();
    return 0;
}

      

The constructor first resizes the vector by 5 elements. After that, it pushes 5 more elements towards the vector, making it twice as large, and the first 5 elements are initialized to 0.

If you were using the fallback function, the vector size would only be 5 * sizeof (int) with predefined memory.



Using:

vectorInt[i] = i;

      

instead, together with the resize constructor will cause the vector to be the same size as if you were using the fallback and not selecting std :: bad_alloc.

The reason for std :: bad_alloc is most likely you are running out of memory.

0


source


hlt already answered this in a comment ...

The constructor is not reserve

, it resize

s. Is it possible that you just ran out of memory?

... so posting the explanation as a wiki community ...

It...

std::vector<int>* intVector = new std::vector<int>(elemNumber); // throws bad_alloc

      



... the vector needs to be populated with the default generated elements, so it writes all the memory pages needed for elemNumber

int

s, and the initial one size()

is elemNumber

, whereas ...

std::vector<int>* intVector = new std::vector<int>();
intVector->reserve(elemNumber); //OK

      

... just reserves virtual addresses for memory - the operating system does not need to find the actual memory of memory until items are added later; initial size()

still 0

.

Then the program goes to the push_back

set of elements - for the first case, in addition to those elements that were built by default, they are already in vector

, so it runs out of memory.

Remember also that the memory instantly used when resizing (caused push_back

out of bounds capacity

) increases as the container grows, as does the amount the container tends to swap capacity, so it won't have to resize too quickly, and any memory needed must be contiguous in the virtual address space (which is primarily a potential problem for a 32-bit application).

+2


source


I am getting an exception bad_alloc

on MSVS2015 RC. However, bad_alloc

it is not found in the construction line.

First this line:

std::vector<int>* intVector = new std::vector<int>(elemNumber);

      

allocates storage for 100,000,000 integers and then a loop:

for (int i = 0; i < elemNumber; ++i)
{
    intVector->push_back(i);
}

      

adds another 100,000,000 integers where at some point on the way to 200,000,000 (150,000,000 in my case) is bad_alloc

selected.

In fact, MSVC calls _Reallocate

for 225000000

values, since there is a function _Grow_to

that tries to grow to 50%

match as much as possible max_size()

.

0


source







All Articles