我正在撰写一些对性能至关重要的内容,并想知道如果我使用它会是否会产生影响:
int test( int a, int b, int c )
{
// Do millions of calculations with a, b, c
}
或
class myStorage
{
public:
int a, b, c;
};
int test( myStorage values )
{
// Do millions of calculations with values.a, values.b, values.c
}
我确信这对C ++专家来说很明显,所以我现在不会尝试为它写一个不切实际的基准
答案 0 :(得分:5)
编译器可能会对它们进行均衡。如果它有任何大脑,它会将values.a
,values.b
和values.c
复制到局部变量或寄存器中,这也是简单情况下的情况。
相关格言:
过早优化是多恶的根源。
写下来,以便您可以在六个月后的凌晨1点阅读,并且仍然能理解您的目的。
大多数情况下,重要的优化来自重构算法,而不是变量访问方式的微小变化。是的,我知道有例外,但这可能不是其中之一。
答案 1 :(得分:4)
这听起来像是过早优化。
话虽如此,但存在一些差异和机会,但它们会影响对函数的多次调用,而不是函数中的性能。
首先,在第二个选项中,您可能希望将MyStorage作为常量引用传递。 因此,您编译的代码可能会将单个值压入堆栈(以允许您访问容器),而不是推送三个单独的值。如果你有其他字段(除了a-c),发送MyStorage不作为参考实际上可能会花费更多,因为你将调用一个复制构造函数并基本上复制所有其他字段。所有这些都是每次通话的费用,而不是在功能范围内。
如果你在函数中使用b和c进行大量计算,那么转移或访问它们的方式并不重要。如果你通过引用传递,初始成本可能稍微多一些(因为你的对象,如果通过引用传递,可能在堆而不是堆栈上),但是一旦第一次访问,你的机器上的缓存和寄存器可能会意味着低成本访问。如果你已经按值传递了对象,那么它确实无关紧要,因为即使最初,这些值也会在堆栈附近。
对于您提供的代码,如果这些是唯一的字段,则可能没有区别。 “values.variable”仅被解释为堆栈中的偏移量,而不是“查找一个对象,然后访问另一个地址”。
当然,如果您不购买这些参数,只需将局部变量定义为函数的第一步,复制对象中的值,然后使用这些变量。如果你真的多次使用它们,这个副本的初始成本无关紧要:)
答案 2 :(得分:0)
不,你的cpu会缓存你一遍又一遍使用的变量。
答案 3 :(得分:0)
我认为有一些开销,但可能不会太多。因为对象的内存地址将存储在指向堆内存对象的堆栈中,所以您可以访问实例变量。
如果将变量int存储在堆栈中,它会更快,因为该值已经在堆栈中,并且机器只是去堆栈以计算出来:)。
它还取决于您是否将类的实例变量值存储在堆栈上。如果在test()中,你会喜欢:
int a = objA.a;
int b = objA.b;
int c = objA.c;
我认为这几乎是相同的表现
答案 4 :(得分:0)
如果您真的在编写性能关键代码,并且您认为一个版本应该比另一个版本更快,请编写两个版本并测试时序(使用正确的优化开关编译代码)。您甚至可能希望查看生成的汇编代码。很多事情都会影响代码片段的速度,这些代码片段非常微妙,比如寄存器溢出等。
答案 5 :(得分:0)
你也可以用
开始你的功能int & a = values.a;
int & b = values.b;
虽然编译器应该足够聪明,可以在幕后为您完成。一般来说,我更喜欢传递结构或类,这使得函数通常更清楚,而且每次想要考虑另一个参数时都不必更改签名。
答案 6 :(得分:0)
与之前的类似问题一样:它取决于编译器和平台。如果有任何差异,它将非常小。
堆栈上的值和对象中的值通常使用指针(堆栈指针或this
指针)和一些偏移量(函数的堆栈框架中的位置,或者内部的位置)来访问类)。
以下是一些可能会产生影响的案例:
根据您的平台,堆栈指针可能保存在CPU寄存器中,而this
指针可能不会。如果是这种情况,访问this
(可能在堆栈上)将需要额外的内存查找。
内存位置可能不同。如果内存中的对象大于一个缓存行,则字段将分布在多个缓存行中。在堆栈帧中仅将相关值放在一起可能会提高缓存效率。
请注意,我在这里经常使用“可能”这个词。唯一可以确定的方法就是测量它。
答案 7 :(得分:0)
如果无法对程序进行概要分析,请打印出代码片段的汇编语言。
通常,较少的汇编代码意味着执行的指令较少,从而加快了性能。当分析器不可用时,这是一种粗略估计性能的技术。
汇编语言列表将允许您查看实现之间的差异(如果有)。