C++ 我们应该为函数的返回值使用临时变量吗?
我想了想:这两种实践中是否存在性能差异:C++ 我们应该为函数的返回值使用临时变量吗?,c++,performance,C++,Performance,我想了想:这两种实践中是否存在性能差异: 将函数的返回值存储在临时变量中,而不是 将该变量作为另一个函数的参数 将该函数放入另一个函数中 规范 假设所有类和函数都编写正确 案例1。 案例2。 我知道只有一次运行没有太大的区别,但是假设我们可以在一个循环中运行很多次,我创建了一些测试 试验 #包括 #包括 #包括 使用名称空间std; int main() { 时钟启动=时钟(); 时钟结束=时钟(); //案例1。 开始=时钟(); 对于(int i=0;i如果您希望计算更为紧凑,并且您的数字更
#包括
#包括
#包括
使用名称空间std;
int main()
{
时钟启动=时钟();
时钟结束=时钟();
//案例1。
开始=时钟();
对于(int i=0;i如果您希望计算更为紧凑,并且您的数字更为一致,请打破一次性优化。确保获得正确值的代码实际运行,而不是完全抛出,我已将两个测试中的结果分配给易失性局部优化(这并不是volatile的正确用法,但在确保只有价值创造才是重要的增量方面做得很好)
对上述两个循环进行适当且合法的完全优化是“甚至不要执行循环”。您可能很容易看到这样一种情况:您在第一种情况下使用未初始化的变量混淆了编译器,或者您对变量的使用混淆了它,或者您的优化级别强制命名变量实际存在
现在,在C++11中,涉及临时变量隐式移动的两个变量之间存在差异,但是您可以使用std::move
(我不确定,但是最后一次使用超出范围的局部变量可能符合隐式移动的条件)。对于double
来说,这并没有什么区别,但对于更复杂的类型来说,这可能会有区别。第二个更慢?对我来说似乎快得多。优化编译器应该能够使这两种情况完全相同。。除非在第一种情况下调用UB。@Linuxios:结果永远不会被接受。这在正常优化编译器的能力范围内如果要删除像这样的内在函数调用,那么它不知道有什么副作用,但是不会取值。@Linuxiossqrt
,sin
和cos
是内置的,可能编译器知道它们没有任何副作用,所以sqrt(pow(cos(1),2));
相当于(例如)((void)0);
-一个没有效果的表达式,只是一个悬而未决的值……两个循环的适当充分优化是“不要做循环”。您需要更好的测试。上次使用超出范围的变量不符合隐式移动的条件。隐式移动仅发生在可能发生复制省略的地方--返回
s个局部变量(其中变量的类型与返回值的类型匹配),抛出在捕获
之前超出范围的变量,临时副本和异常的捕获
副本(异常类型完全匹配).我明白你所说的,但这不是在强化我们应该像案例2那样编写代码,因为编译器优化了吗?@totymedli不太可能,人们可以很容易地说,第一种方法的清晰性比第二种方法更能吸引开发者的眼球,因为优化器抛出了a
和b
(在本例中)最终结果是一样的。对于非平凡的值类型,每种方法是好的还是坏的,这是一个比我更好地理解RVO(返回值优化)的人可能会更好地回答的问题。对于这种特殊情况,可能会生成相同或近似相同的代码。
ClassA a = function1();
ClassB b = function2(a);
function3(b);
function3(function2(function1()));
#include <iostream>
#include <ctime>
#include <math.h>
using namespace std;
int main()
{
clock_t start = clock();
clock_t ends = clock();
// Case 1.
start = clock();
for (int i=0; i<10000000; i++)
{
double a = cos(1);
double b = pow(a, 2);
sqrt(b);
}
ends = clock();
cout << (double) (ends - start) / CLOCKS_PER_SEC << endl;
// Case 2.
start = clock();
for (int i=0; i<10000000; i++)
sqrt(pow(cos(1),2));
ends = clock();
cout << (double) (ends - start) / CLOCKS_PER_SEC << endl;
return 0;
}
#include <iostream>
#include <ctime>
#include <cmath>
using namespace std;
int main()
{
clock_t start;
volatile double val;
for (int j=1;j<=10;j++)
{
// Case 1.
start = clock();
for (int i=0; i<2000000; i++)
{
double a = cos(1);
double b = pow(a, 2);
val = sqrt(b);
}
cout << j << ':' << (double) (clock() - start) / CLOCKS_PER_SEC << endl;
// Case 2.
start = clock();
for (int i=0; i<2000000; i++)
val = sqrt(pow(cos(1),2));
cout << j << ':' << (double) (clock() - start) / CLOCKS_PER_SEC << endl << endl;
}
return 0;
}
1:0.001465
1:0.001305
2:0.001292
2:0.001424
3:0.001297
3:0.001351
4:0.001366
4:0.001342
5:0.001196
5:0.001376
6:0.001341
6:0.001303
7:0.001396
7:0.001422
8:0.001429
8:0.001427
9:0.001408
9:0.001398
10:0.001317
10:0.001353