通过构造函数为vector预分配内存失败



我使用VS2013 (Win7 64)。我发现了一些奇怪的行为。当我使用reserve方法保留内存时,代码可以工作,但是当我通过构造函数保留内存时,它抛出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;
}

原因是什么?

hlt已经在评论中回答了这个问题…

构造函数不reserve,它resize s。有没有可能是内存用完了?

…所以在社区wiki上发布一个解释…

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

…需要用默认构造的元素填充向量,因此它正在写入elemNumber int s所需的所有内存页面,并且初始size()elemNumber,而…

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

…只是为内存保留虚拟地址——操作系统不需要找到实际的后备内存,直到稍后添加元素;初始size()仍然是0

程序然后进入push_back许多元素-对于第一种情况,它们是在vector中已经存在的默认构造元素的之外的,这就是它耗尽内存的原因。

还请记住,在调整大小期间(由push_back超过capacity引起)暂时使用的内存随着容器变大而增加,容器倾向于填充容量的数量也会增加,因此它不必很快再次调整大小,并且所需的内存必须在虚拟地址空间中连续(这主要是32位应用程序的潜在问题)。

看一下下面的例子:

#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;
}

构造函数首先将vector的大小调整为5个元素。之后,再将5个元素压入vector容器,使vector容器的大小翻倍,并将前5个元素初始化为0。

如果使用保留函数,则vector的大小只有5*sizeof(int)和预分配的内存。

使用:

vectorInt[i] = i;

与resize构造函数一起使用,将使vector的大小与使用reserve相同,并且不会抛出std::bad_alloc。

std::bad_alloc的原因很可能是内存耗尽。

我也得到了MSVS2015 RC上的bad_alloc异常。然而,bad_alloc不出现在构造行中。

第一行

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

为100000000个整数分配存储空间,然后循环:

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

增加了另外100000000个整数,在到达200000000(在我的例子中是150000000)的某个点上抛出bad_alloc

实际上,MSVC为225000000值调用_Reallocate,因为有一个函数_Grow_to,如果可能的话,根据max_size(),它试图通过50%增长。

最新更新