我有以下功能:
double
neville (double xx, size_t n, const double *x, const double *y, double *work);
,利用x
和y
中存储的n
点对xx
进行拉格朗日插值。work
数组的大小为2 * n
。由于这是多项式插值,n
在~5的范围内,很少超过10。
这个函数是积极优化的,应该在紧密循环中调用。分析表明,在循环中堆分配工作数组是不好的。不幸的是,我应该将其打包到一个类似函数的类中,并且客户机必须不知道工作数组。
现在,我使用一个模板整数参数来表示度数和std::array
,以避免work
数组的动态分配:
template <size_t n>
struct interpolator
{
double operator() (double xx) const
{
std::array<double, 2 * n> work;
size_t i = locate (xx); // not shown here, no performance impact
// due to clever tricks + nice calling patterns
return neville (xx, n, x + i, y + i, work.data ());
}
const double *x, *y;
};
可以将工作数组存储为类的可变成员,但是operator()
应该由多个线程并发使用。如果您在编译时知道n
,则此版本是可以的。
现在,需要在运行时指定n
参数。我想知道这样的事情:
double operator() (double xx) const
{
auto work = static_cast<double*> (alloca (n * sizeof (double)));
...
当使用alloca
时,有些铃声响起:我当然要对n
设置一个上限,以避免alloca
调用溢出(无论如何,使用100度多项式插值是相当愚蠢的)。
然而,我对这种方法感到很不舒服:
- 我错过了
alloca
的一些明显危险吗? - 是否有更好的方法来避免堆分配?
然而,我对这种方法感到很不舒服:
- 我是否错过了一些明显的分配危险?
你指出了一个真正的危险:alloca
没有定义堆栈溢出行为。此外,alloca
实际上并没有标准化。例如,Visual c++有_alloca
,而GCC在默认情况下将其定义为宏。但是,通过为少数现有实现提供一个薄包装器,可以相当容易地规避这个问题。
- 是否有更好的方法来避免堆分配?
没有。c++ 14将有一个(潜在的!)堆栈分配的可变长度数组类型。但在那之前,当你认为std::array
不太合适时,在你这样的情况下,选择alloca
。
一个小问题:你的代码缺少对alloca
返回值的强制转换。它甚至不能编译
对于堆栈内存的任何使用,总是有一堆注释要添加。正如你所指出的,堆栈的大小是有限的,当空间耗尽时,会出现相当严重的错误行为。如果有保护页,堆栈溢出可能会崩溃,但在某些平台和线程环境中,有时可能是无声的损坏(坏)或安全问题(更糟)。
还请记住,堆栈分配与malloc
相比非常快(它只是从堆栈指针寄存器中减去)。但是使用该内存的可能不是。将堆栈帧大量下压的副作用是,您将要调用的叶函数的缓存行不再驻留。因此,对该内存的任何使用都需要到SMP环境中,以使缓存线恢复到独占(MESI意义上的)状态。SMP总线是一个比L1缓存更受约束的环境,如果您在周围散布堆栈帧,这可能是一个真正的可伸缩性问题。
另外,就语法而言,请注意gcc和clang(我相信还有Intel的编译器)都支持C99可变长度数组语法作为c++扩展。您可能根本不需要调用libc alloca()
例程。
最后,请注意malloc
真的不是那么慢。如果您正在处理几十kb或更大的单个缓冲区,那么为您要在其上执行的任何工作提供服务所需的内存带宽将淹没malloc
的任何开销。
基本上:alloca()
是可爱的,有它的用途,但除非你有一个基准准备证明你需要它,你可能不应该,应该坚持传统的分配。
这个怎么样:
double operator() (double xx) const
{
double work_static[STATIC_N_MAX];
double* work = work_static;
std::vector<double> work_dynamic;
if ( n > STATIC_N_MAX ) {
work_dynamic.resize(n);
work = &work_dynamic[0];
}
///...
没有不可移植的特性,异常安全,并且在n
过大时优雅地降级。当然,您可以将work_static
改为std::array
,但我不确定您从中看到了什么好处。