【问题标题】:Avoiding memcpy in C++ buffered output在 C++ 缓冲输出中避免 memcpy
【发布时间】:2011-04-27 04:35:28
【问题描述】:

我正在尝试直接写入 fstream 输出缓冲区以避免memcpy

为什么下面的代码不起作用?

它在 Linux 上编译、运行并生成正确长度的输出文件。但输出文件不包含正确的文本。另请注意,由于某种原因,当我注释掉涉及str2 的两行时,会生成一个长度为零的输出文件。

注意:这个例子没有避免memcpy,但如果它有效,它将帮助我在我的应用程序中避免memcpy

#include <fstream>

int main(int argc, char *argv[]) {
  std::fstream out;
  char buffer[512];
  out.rdbuf()->pubsetbuf(buffer, 512);
  out.open("file.txt", std::fstream::out);
  char *str1 = "test text.";
  strcpy(buffer, str1);
  out.rdbuf()->pubseekpos(strlen(str1), std::ios_base::out);
  char *str2 = "why?";
  out << str2;
  out.flush();
  out.close();
}

【问题讨论】:

  • to avoid a memcpy -- 抱歉,这很愚蠢。 memcpy 是最快的操作之一。
  • 您确定memcpy 的成本与实际完成的I/O 成本相比实际上很重要吗?你剖析过吗?这可能只是一个过早的优化,您应该将精力集中在其他地方。
  • 关于“为什么”我这样做有几个问题。让我们暂时忽略这些。底线是代码不会生成带有文本的输出文件:“测试文本。为什么?”谁能告诉我为什么?
  • @Xeo:你回答一个没有被问到的问题不仅很烦人,而且你也错了。虽然 memcpy() 速度很快,但它的成本是可衡量的,消除它可以产生显着的性能优势,比如我在我编写的解析器中测量的 10% 的优势:article.gmane.org/gmane.comp.lang.lua.general/77955
  • @Josh:“通过回答” - 我把它作为评论完全是因为它不是一个答案。

标签: c++ linux fstream buffered


【解决方案1】:

你给流一个缓冲区供它的内部使用。那你就不给它写东西了。

您将某些内容复制到缓冲区而不告诉流这一事实并没有为您提供文件中的任何内容。

您可能已经注意到,seekpos 用于在文件中定位,而不是在缓冲区中移动。缓冲区仅供流内部使用!

【讨论】:

    【解决方案2】:

    当您out.rdbuf()-&gt;pubseekpos(strlen(str1), std::ios_base::out); 时,这会要求流向前跳过新创建的文件。您能期望它从您指定的缓冲区中获取内容吗?一条线索:您是否看到任何涉及指定缓冲区的示例,这些示例表明您需要以某种方式对其进行初始化或指定其中包含的非垃圾字符的初始数量?不...因为流本身会跟踪缓冲区的哪些部分正在使用中。因此 - 当您使用假定的空缓冲区并向前跳过时,它会生成中间的 NUL。将它们设置在缓冲区中是没有意义的(因此在 pubseekpos 之后简单地执行 memcpy 也不起作用) - 如果您向前跳跃超过缓冲区大小怎么办?

    希望这至少能说明问题,尽管在这个阶段我没有考虑过如何强制流改变它对有意义的缓冲区内容的“跟踪”......

    【讨论】:

      【解决方案3】:

      现在还早,但你不是基本在做吗

      #include <fstream>
      
      int main(int argc, char *argv[]) 
      {
      
        std::fstream out;
        out.open("file.txt", std::fstream::out);
      
        out << "test text";
        out << "why?";
      
        out.flush();
        out.close();
      }
      

      ?

      【讨论】:

      • 在这个例子中,是的!但是我可以直接(读取指针)访问输出缓冲区吗?
      • 你想达到什么目的?因为你没有调用任何写操作,所以我很确定某些实现不会写任何东西。您正在操作内存但不写入文件。你真正想做的是什么?
      • @user 没有,但我相信你可以将它复制到堆中。
      【解决方案4】:

      我对 C++ iostream 库不够熟悉,无法说出你的程序出了什么问题,我只想提一下,如果你想自己做缓冲,使用 read() 和 write 可能会更直接() 直接接口(man 2 write)。如果你自己做缓冲,iostream 库可能不会给你带来太多好处,只会掩盖实际发生的事情。

      【讨论】:

        【解决方案5】:

        我看到了三种可能性

        1. 实现您自己的流缓冲类
        2. 使用本机文件 API
        3. 使用pubsetbuf(0, 0) 禁用缓冲

        实现一个流缓冲实际上并没有那么困难,并且可以让您有机会将 C++ 风格的流插入与直接内存访问相结合,而无需 牺牲性能。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-09-20
          • 2014-11-17
          • 1970-01-01
          • 1970-01-01
          • 2013-02-07
          • 2012-10-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多