c++ - C++中的有效循环缓冲区,将传递给C样式数组函数参数

标签 c++ arrays circular-buffer

我正在寻求有关解决以下问题的建议。我有一个恒定的数据输入,需要将其添加到缓冲区中,并且在每次迭代时,我都需要将缓冲的数据传递给通过指针接受C样式数组的函数。
我担心效率,因此我考虑了如何在某种循环缓冲区中存储和管理数据,但又将其作为顺序的原始数据来传递给上述功能。
我的当前方法可以总结为以下示例:

#include <iostream>
#include <array>
#include <algorithm>

void foo(double* arr, int size)
{
  for (uint k = 0; k < size; k++)
    std::cout << arr[k] << ", ";

  std::cout << std::endl;
}

int main()
{
  const int size = 20;
  std::array<double, size> buffer{};

  for (double data = 0.0; data < 50.0; data += 1.0)
  {
      std::move(std::next(std::begin(buffer)), std::end(buffer), std::begin(buffer));
      buffer.back() = data;

      foo(buffer.data(), size);
  }
}
在实际用例中,还需要在开始时将缓冲区填充为数据的“const”大小(我在这里使用引号,因为在编译时可能知道或可能不知道大小,但是一旦知道,它就会永远不会改变)。
我将数据存储在std::array中(如果在编译时未知大小,则存储在std::vector中),因为数据在内存中是顺序的。当我需要插入新数据时,我使用正向std::move移动所有内容,然后手动替换最后一个项目。最后,我只是将std::array::data()及其大小传递给该函数。
乍一看这应该有效,但原因告诉我,由于数据是按顺序存储的,因此整个缓冲区仍将使用std::move复制,并且每个插入均为O(n)
实际的缓冲区大小可能只有几百个,并且数据将以最大100Hz的频率到达,但是问题是我需要尽快获得被调用函数的结果,所以我不想浪费时间进行缓冲区管理(即使我们说话很少,甚至少于毫秒)。我对此有很多疑问,但他们的候选名单如下​​:
  • 我的方法太天真了吗?
  • 我对O(n)的推理正确吗?
  • 这种方法还有其他陷阱吗?
  • 您对我应该研究的其他方法有建议吗?
  • 最佳答案

    感谢您的回答沃纳。当我在Repl.it上运行此解决方案时,我得到:

    it took an average of 21us and a max of 57382us
    
    为了进行比较,我最初的想法是使用相同的缓冲区大小,结果如下:
    it took an average of 19us and a max of 54129us
    
    这意味着我最初的方法确实很幼稚:)
    同时,在等待答案的同时,我提出了以下解决方案:
    #include <iostream>
    #include <array>
    #include <algorithm>
    #include <chrono>
    
    void foo(double* arr, int size)
    {
      for (uint k = 0; k < size; k++)
        std::cout << arr[k] << ", ";
    
      std::cout << std::endl;
    }
    
    int main()
    {
      const int buffer_size = 20;
      std::array<double, buffer_size*2> buffer{};
      int buffer_idx = buffer_size;
    
      for (double data = 0.0; data < 100.0; data += 1.0)
      {
        buffer.at(buffer_idx - buffer_size) = data;
        buffer.at(buffer_idx++) = data;
    
        foo(buffer.data() + buffer_idx - buffer_size, buffer_size);
    
        buffer_idx -= buffer_size * (buffer_idx == buffer_size * 2);
      }
    }
    
    由于缓冲区的大小不是问题,因此我分配了两倍的内存,并在两个位置插入了数据,但偏移了缓冲区的大小。当我到达终点时,我就像打字机一样回去。我的想法是,我通过再存储一个数据副本来伪造循环缓冲区,这样它就可以读取数据,就像它越过了整个圆圈一样。
    对于50000的缓冲区大小,这给出了我想要的以下结果:
    it took an average of 0us and a max of 23us
    

    关于c++ - C++中的有效循环缓冲区,将传递给C样式数组函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62892744/

    相关文章:

    c++ - 制作特殊组合 (C++)

    java - 可以使用线性搜索来查找循环(​​循环)数组中的最小数字

    c++ - 与竞争特定内存地址(互斥锁暂停另一个)相比,circularBuffer 如何提高性能?

    c++ - 插入 Asus Xtion Pro 时无法使用 OpenCV 从网络摄像头获取图片

    c++ - LLVM 查找每条分配内存的指令

    c++ - 3维数组的重新分配

    c - 为什么会损坏声音?

    c++ - back_insert_iterator<> 按值传递安全吗?

    c++ - FLTK 按钮回调给 c3867

    python - Numpy 以特定顺序 reshape 数组