【问题标题】:Will this method involve memory reallocation and thus influence its efficiency?这种方法是否会涉及内存重新分配,从而影响其效率?
【发布时间】:2020-03-02 08:41:17
【问题描述】:

我发现我们可以像这样将文件的内容读入 std::vector:

  ifstream fin(..., ios::in);
    std::vector<char> buf(
            std::istreambuf_iterator<char>(fin), 
            std::istreambuf_iterator<char>());   

这种方法会不会像我多次调用buf.push_back(); 那样导致大量的内存重新分配?将文件读入std::vector 的最快或最佳方法是什么?

编辑: 顺便说一句,我发现有一种方法可以将文件读入字符串流:

stringstream ss;
ifstream fin(..., ios::in);
fin >> ss.rdbuf();

这种方法会不会有同样的内存重新分配问题?

【问题讨论】:

  • 重新分配所花费的时间与 IO 所花费的时间相比是微不足道的。

标签: c++ file vector ifstream


【解决方案1】:

std::istreambuf_iterator是一个输入迭代器,所以begin和end之间的距离是事先不知道的。除非文件非常小,否则在构造过程中会有几次重新分配。对于随机访问迭代器,距离是已知的,在这种情况下,构造函数可以避免额外的内存分配。

如果你大致知道文件的大小,可以在阅读前使用reserve()

std::vector<char> buf;
buf.reserve(file_size);
buf.insert(buf.end(), std::istreambuf_iterator<char>(fin), 
        std::istreambuf_iterator<char>());   

【讨论】:

  • 读取文件的大小,保留这么多空间,然后重新开始读取向量会使其效率低下。与在 IO 中花费的时间相比,重新分配的时间可以忽略不计。特别是当输入文件很大时,因为seekg 必须检查整个文件才能获得大小。
  • @theWiseBro 重新分配 N 字节而不是 M 字节涉及分配 N 字节,复制所有信息,然后取消分配旧存储。对于大量数据,这是低效的。如果保留是一个问题,则可以使用无需重新分配的存储,例如。预定义块的列表。
  • @Swift-FridayPie 让我们简化一下。假设 n 个字节的时间,memcpy 需要 N 个单位。重新分配的总时间 = N+N/2+N/4... = 2*N。假设 OP 有一个 nvme ssd。即使这样,从内存中的传输也超过 10 倍 ~ 10N。阅读两次 = 20*N。这是最好情况下差异的 10 倍(假设我的计算是正确的)。
  • @theWiseBro 这就是为什么在任何现代文件系统中您无需读取文件即可知道其大小的原因,哈哈。那你最好设计文件格式以在标题中存储精确的数据大小和偏移量。
【解决方案2】:

Vector 保持按顺序分配的数据。 当添加一个新元素时,它可能在最后一个元素之后没有可用的内存,那么它需要将所有数据移动到内存中一个有足够空间容纳新旧数据的地方。

最好的解决方案是使用以下命令为向量提供缓冲区:vector::reserve(size);

您的代码可能是:

std::vector<char> buf;
buf.reserve(10000);
buf.assign(std::istreambuf_iterator<char>(fin),
            std::istreambuf_iterator<char>());
buf.shrink_to_fit(); //free the unused memory

【讨论】:

  • 如果文件有 10 个字符,这不是很有效
  • 这与已经提供的答案基本相同...顺便说一句,std::vector::shrink_to_fit() 可能会执行整个向量的重新分配。我不确定是否值得在这里冒险。
  • @Fareanor 类似。关于vector::shrink_to_fit,在cppreference.com 和cplusplus.com 网站上说它只是“减少vector::size 的容量”。释放内存时无法重新分配。
  • @idclev 您可以使用 istream::tellg() 方法读取文件大小而不是使用文字值。看看这里:codeyarns.com/2018/02/02/how-to-find-size-of-file-in-c。那么 vector::shrink_to_fit 将是不必要的,但如果你得到一个大文件,它就不会有效。您需要选择更适合您的程序的方法。
  • 减少容量意味着重新分配。文档对此很清楚:en.cppreference.com/w/cpp/container/vector/shrink_to_fit
猜你喜欢
  • 1970-01-01
  • 2018-07-29
  • 1970-01-01
  • 1970-01-01
  • 2020-05-27
  • 1970-01-01
  • 2014-08-18
  • 2019-03-25
  • 1970-01-01
相关资源
最近更新 更多