带引用参数的递归constexpr函数为何比传值参数的版本快得多?
带引用参数的递归constexpr函数为何比传值参数的版本快得多?
嘿,咱们先把问题里用到的代码亮出来——这是你给出的constexpr斐波那契递归函数:
constexpr auto fibo(unsigned int number) -> unsigned long long { if (number < 2) return number; return fibo(number - 1) + fibo(number - 2); }
你提到用基准测试代码跑过之后,得到了这样的部分输出:
benchmark name samples iterations est run time mean
那咱们来唠唠为什么带引用参数的版本会快这么多:
- 首先说传值的坑:递归调用时,每次传值都会复制一份
unsigned int。别小看这个小类型的复制,斐波那契递归是指数级的调用次数,比如算fibo(30)就有几十万次调用,累计下来的复制开销就很可观了。 - 再看传引用的优势:如果把参数改成
const unsigned int& number,在编译期求值阶段,编译器会直接绑定到原值的存储位置,完全不需要复制。就算是运行时调用,引用也只是传递一个地址,比复制值更轻量,还能减少栈上的临时对象,减轻栈的压力。 - 还有编译器优化的加成:因为是
const引用,编译器能100%确定参数值不会被修改,所以可以放心地做常量传播、调用展开甚至缓存中间结果,直接减少很多重复计算的步骤,这对递归函数的性能提升是巨大的。 - 另外,
constexpr函数的编译期求值对参数处理更敏感:传值的话,每次调用都相当于生成一个新的常量实例,而传引用可以复用同一个常量的标识,编译器的常量折叠优化能做得更彻底。
总结一下,核心就是传值的递归会产生大量重复的小对象复制,而传引用版本完全避免了这一点,再加上编译器针对const引用的更强优化,就导致了性能的巨大差距。
备注:内容来源于stack exchange,提问作者TheJanzap
相关产品推荐
相关产品推荐

