向量通过构造函数的C ++内存预分配失败

时间:2015-07-23 10:56:47

标签: c++ c++11 stl

我使用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;
}

可能是什么原因?

3 个答案:

答案 0 :(得分:2)

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

  

构造函数不是reserve,而是resize。你有可能只是内存不足吗?

...所以将解释发布为社区维基...

此...

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

...需要使用默认构造的元素填充向量,因此它写入elemNumber int所需的所有内存页面,并且初始size()为{ {1}},而......

elemNumber

...只是为内存保留虚拟地址 - 在稍后添加元素之前,操作系统不需要找到实际的后备内存;最初的std::vector<int>* intVector = new std::vector<int>(); intVector->reserve(elemNumber); //OK 仍为size()

程序然后转到0许多元素 - 对于第一种情况,它们另外已经存在于push_back中的那些默认构造元素中,这就是为什么它的内存不足。

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

答案 1 :(得分:0)

我也在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个整数,在某个点上,在200,00000(在我的情况下为150000000)bad_alloc被抛出的路上。

实际上,MSVC会针对_Reallocate值调用225000000,因为有一个函数_Grow_to根据50%尝试增加max_size()。< / p>

答案 2 :(得分:0)

看看下面的例子:

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

构造函数首先调整向量的大小以包含5个元素。之后,它将5个元素推送到向量,使其大小加倍,前5个元素初始化为0.

如果你要使用保留函数,那么向量的大小只有5 * sizeof(int)和预分配的内存。

使用:

vectorInt[i] = i;

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

std :: bad_alloc的原因很可能就是内存不足。