2

我正在将三个大型二进制文件(每个 c.180Mb)读入 std::vector 如下:

m_ifStream.open("myfile.dat", std::ios::binary | std::ios::in);

if (m_ifStream)
{
    //Obtain input stream length
    m_ifStream.seekg (0, ios::end);
    streamLength = (size_t)(m_ifStream.tellg());
    m_ifStream.seekg (0, ios::beg);

    //Reserve doesn't work around the problem, may be more efficient though...
    //m_buffer = new vector<unsigned char>();
    //m_buffer->reserve(streamLength);

    //Next line sometimes results in bad_alloc when reading a large file
    m_buffer = new vector<unsigned char>((std::istreambuf_iterator<char>(m_ifStream)), (std::istreambuf_iterator<char>()));
}

填充向量的调用失败,引发“错误分配”异常。

读取第一个文件时填充有时会失败;在其他时候,它在第二次或第三次失败。我正在使用 Visual Studio 2010 并将我的代码编译为 32 位,它应该能够寻址高达 2Gb。我在一台 16Gb RAM 的机器上运行,至少有 10Gb 可用,所以可用内存不足不是问题。该错误发生在调试和发布配置中。

预先分配内存reserve并没有帮助。

向量的max_size属性返回 2^32,因此它似乎不是容器中的限制。

该代码适用于大量合并大小> 180Mb 的较小文件,这使我认为我的代码达到了边界。

是否有一种可接受的方式从大型输入文件中填充向量?我想避免遍历文件中的每个字节,并认为 usingistreambuf_iterator 会针对这种操作进行优化。

4

3 回答 3

2

如果你想让你的调用对reserve()实际读数产生任何影响,你不应该创建一个临时的std::vector<unsigned char>并将这个临时分配给目标向量。相反,您使用类似的东西

m_buffer->assign(std::istreambuf_iterator<char>(m_ifStream),
                 std::istreambuf_iterator<char>());

在不保留的情况下读取文件可能会以某种方式分散您的内存,但我不希望程序会因为像您这样的小文件而耗尽内存(几 GB 的文件可以被认为是大的;160MB 并不是真的大的)。如果您知道文件的大小,则最好使用read()成员读取文件,但是:

m_buffer->resize(streamLength);
m_ifStream.read(reinterpret_cast<char*>(m_buffer->data()), streamLength);

我个人的猜测是,std::bad_alloc异常实际上是由确定文件大小的错误引起的。例如,我认为它std::size_t不一定大到足以容纳一个std::streamsize. 此外,没有尝试验证任何这些操作是否成功,如果流无法打开,seekg()将返回pos_type(-1),这将转换为相当大的std::size_t.

于 2013-10-12T19:34:17.630 回答
1

您正在做更多的工作并分配比您需要的更多的内存。

首先删除指针,它没有添加任何内容

vector<char> m_buffer;

然后调用resize(不是reserve)到正确的大小

m_buffer.resize(streamLength);

如果您要耗尽内存,这就是它会发生的时候。

最后将数据直接读入vector,不要使用streambuf_iterator,谁知道幕后是什么

m_ifStream.read(&m_buffer[0], streamLength);

这里的主要好处是你只分配一个向量(你的代码有两个向量,其中一个被复制到另一个之上),其次你已经删除了所有的绒毛,只留下了两个基本操作,分配内存,读取文件。

于 2013-10-12T19:37:12.063 回答
0
m_buffer = new vector<unsigned char>();
m_buffer->reserve(streamLength);

//Next line sometimes results in bad_alloc when reading a large file
*m_buffer = vector<unsigned char>((std::istreambuf_iterator<char>(m_ifStream)), (std::istreambuf_iterator<char>()));

让我印象深刻的第一件事是你正在覆盖一个已经预先分配的区域vector。如果您随后创建一个新向量来覆盖该向量,那么执行“保留”显然没有意义。这只是意味着您必须为这两个相对较大的向量留出空间。

我将首先更改m_buffer为不是指向向量的指针-这样,您不必调用new vector<unsigned char>-拥有指向向量的指针几乎没有用[充其量,您可以节省大约 16 个字节,如果您有不包含任何内容的向量]。

然后删除reserve. 看看情况如何。

于 2013-10-12T19:25:18.477 回答