最佳做法:在函数中频繁使用大时态缓冲区 (C++)

Best Practice: Frequent usage of big temporal buffer within function (C++)

本文关键字:缓冲区 C++ 函数 最佳      更新时间:2023-10-16

我经常遇到一个问题,我得到一个函数,它需要更大的内存来进行一些内部计算。 该函数将以高频率调用。 可能是内存量太大而无法放入堆栈。因此,我必须分配和释放内存。 但是,我非常担心这种频繁的、不必要的分配/取消分配造成的开销。

我目前看到以下选项:

  1. 每次分配/取消分配
  2. 使用静态变量将内存与共享指针结合使用,以确保安全销毁分配的内存
  3. 使用全局(或文件范围(内存来保持为整个时间分配的内存。
  4. 将函数封装在类中并添加一个保存分配内存的成员变量(这里我最关心的是

关于方法3-4:我最关心的是,实际上这个内存中的值只在这个函数中有效,应该只在那里使用。但是,实际上变量的范围更大,并且很容易误用或意外使用变量。必须明确的是,它不打算在函数之外使用这些变量。 我现在最喜欢的是选项 2。 我很高兴听到您对本案最佳实践方法的意见。

略微修改的问题: 想象一下,我们现在有一个成员方法,而不是一个独立的函数。 在这里,我最喜欢的方法 2 将不再起作用,因为该类的所有实例将共享相同的计算缓冲区。因此,我认为只有两种选择: 1. 每次分配/取消分配 2. 为每个插件使用一个成员变量来保持内存分配。

关于方法 2,我再次得到了一些不信任:成员变量可以被同一类中的所有函数访问,尽管预期范围应该仅用于这个单个成员函数中的临时计算。

也许这个变量的一些命名约定以及注释会有所帮助: 例如

...
private:
/** this variable is only intended to be used temporarily within fct1 */
std::shared_ptr<std::array<double, 10000>> tmpBuffer;
...

您在"略有修改"问题中的方法似乎是合理的。 如果你有一个函数重复操作某些数据片段,这些数据在其他一些作用域中以有限的方式使用,但不是整个程序可以访问的,这可能是一个提示,表明数据和这些函数应该作为成员和方法绑定在一起在同一类中。 定义该类后,可以通过常规方法(如范围、std::shared_ptr或类似方法(更简单地处理其实例的生存期。

此时,除非您有进一步的具体证据表明该类的范围和布局导致了问题,否则明智的做法是相信编译器、CPU 缓存等正在为您做出正确的选择,直到分析数据证明并非如此。

假设您有一个函数F想要使用大型临时缓冲区B

  1. 如果调用频率较高F则不希望每次调用F时都分配和取消分配B

  2. 我不确定您在选项 #2 中的意思。如果B被声明为静态,那么您不会/不应该将其放入shared_ptr中。静态变量具有程序生存期,不能/不应该由智能指针管理。

  3. 从性能的角度来看,使用全局B本质上与使用静态B相同,除了全局其他函数也可以访问B,这似乎并不想要。

  4. 您可以将B封装在类C中,构造一个实例S并将S的引用作为参数传递给F。其他函数将无法访问B,除非您也S传递给它们。

在我看来,在上述 4 个选项中,出于性能原因,您不想做 #1,#2 比 #3 更好,因为可见性更窄,#4 似乎是最灵活的。

通过在 #4 中B的访问器中使用原子操作,您还可以允许多个线程同时调用该函数,同时共享对B的访问。或者,您可以简单地在不应共享同一缓冲区的线程中使用不同的C实例。F是否是类成员方法的静态函数也无关紧要;行为是相同的。

缺点是F现在需要一个额外的参数(C& s(,其生存期需要在程序F之外进行管理。但这本质上是你想要的 - 用于性能优化。