8

关于对象(尤其是字符串),按引用调用比按值调用更快,因为函数调用不需要创建原始对象的副本。使用 const,还可以确保引用不被滥用。

我的问题是,如果使用基本类型(如 bool、int 或 double),const 引用调用是否也更快。

void doSomething(const string & strInput, unsigned int iMode);
void doSomething(const string & strInput, const unsigned int & iMode);

我的怀疑是,只要原始类型的字节大小超过地址值的大小,就使用引用调用是有利的。即使差异很小,我也想利用这个优势,因为我经常调用其​​中一些函数。

附加问题:内联对我的问题的答案有影响吗?

4

5 回答 5

7

我的怀疑是,只要原始类型的字节大小超过地址值的大小,就使用引用调用是有利的。即使差异很小,我也想利用这个优势,因为我经常调用其​​中一些函数。

基于预感的性能调整在 C++ 中大约有 0% 的时间起作用(这是我对统计数据的直觉,它通常有效......)

const T&将小于Tif是正确的sizeof(T) > sizeof(ptr),因此通常是 32 位或 64 位,具体取决于系统。

现在问问自己:

1) 有多少内置类型大于 64 位?

2) 复制 32 位不值得让代码不那么清晰吗?如果您的函数变得明显更快,因为您没有将 32 位值复制到它,也许它没有做太多?

3) 你真的那么聪明吗?(剧透警报:否。)请参阅这个很好的答案,因为它几乎总是一个坏主意: https ://stackoverflow.com/a/4705871/1098041

最终只是通过价值。如果在(彻底)分析之后您发现某个函数是一个瓶颈,并且您尝试的所有其他优化都还不够(并且您应该在此之前尝试其中的大部分),请通过 const-reference 传递。

然后看到它没有改变任何东西。翻身哭泣。

于 2015-03-19T10:43:24.993 回答
4

除了其他答案之外,我还想指出,当您在函数中传递引用并大量使用(也称为取消引用)时,它可能比制作副本要慢。

这是因为函数的局部变量(通常)被一起加载到缓存中,但是当其中一个是指针/引用并且函数使用它时,可能会导致缓存未命中。这意味着它需要去(较慢的)主内存来获取指向的变量,这可能比制作与函数一起加载到缓存中的副本要慢。

因此,即使对于“小对象”,仅按值传递也可能更快。

(我在一本非常好的书中读到这个:计算机系统:程序员的观点

关于整个缓存命中/未命中主题的一些更有趣的讨论:如何编写最能利用 CPU 缓存来提高性能的代码?

于 2015-03-19T10:58:02.830 回答
3

在 64 位架构上,没有比指针/引用更大的原始类型(至少在 C++11 中没有)。const T&您应该对此进行测试,但直观地说,对于 a和对于 an ,应该有相同数量的数据int64_t,而对于任何原语 where 应该更少sizeof(T) < sizeof(int64_t)。因此,只要您可以测量任何差异,如果您的编译器正在做显而易见的事情,按值传递原语应该更快——这就是为什么我强调如果您需要确定性,您应该编写一个测试用例。

另一个考虑因素是原始函数参数可以在 CPU 寄存器中结束,这使得访问它们的速度与内存访问一样快。您可能会发现为您的const T&参数生成的指令比为原始T参数生成的指令多。T您可以通过检查编译器的汇编器输出来测试这一点。

于 2015-03-19T10:43:33.993 回答
2

我被教导:

  • 当参数变量是基本的内置类型之一时,按值传递bool,例如、intfloat。这些类型的对象非常小,以至于通过引用传递并不会提高效率。此外,如果您想复制变量。

  • 当您想要有效地传递不需要更改的值时,传递常量引用。

  • 仅当您要更改参数变量的值时才传递引用。但是要尽量避免更改参数变量。

于 2015-03-19T10:33:03.017 回答
2

const 是在编译时评估的关键字。它对运行时性能没有任何影响。您可以在此处阅读更多相关信息:https ://isocpp.org/wiki/faq/const-correctness

于 2015-03-19T10:41:21.973 回答