了解多个 .和 ->运算符使用?
Understanding cost of multiple . and -> operator use?
当通过访问值时,出于习惯。或者->,每当值要被多次使用时,我都会将它们分配给变量。我的理解是,在像actionscript这样的脚本语言中,这是非常重要的。然而,在C/C++中,我想知道这是否是一件毫无意义的家务事;我是在浪费编译器将要为我处理的工作,还是在进行良好的实践,为什么?
public struct Foo
{
public:
Foo(int val){m_intVal = val;)
int GetInt(){return m_intVal;}
int m_intVal; // not private for sake of last example
};
public void Bar()
{
Foo* foo = GetFooFromSomewhere();
SomeFuncUsingIntValA(foo->GetInt()); // accessing via dereference then function
SomeFuncUsingIntValB(foo->GetInt()); // accessing via dereference then function
SomeFuncUsingIntValC(foo->GetInt()); // accessing via dereference then function
// Is this better?
int val = foo->GetInt();
SomeFuncUsingIntValA(val);
SomeFuncUsingIntValB(val);
SomeFuncUsingIntValC(val);
///////////////////////////////////////////////
// And likewise with . operator
Foo fooDot(5);
SomeFuncUsingIntValA(fooDot.GetInt()); // accessing via function
SomeFuncUsingIntValB(fooDot.GetInt()); // accessing via function
SomeFuncUsingIntValC(fooDot.GetInt()); // accessing via function
// Is this better?
int valDot = foo.GetInt();
SomeFuncUsingIntValA(valDot);
SomeFuncUsingIntValB(valDot);
SomeFuncUsingIntValC(valDot);
///////////////////////////////////////////////
// And lastly, a dot operator to a member, not a function
SomeFuncUsingIntValA(fooDot.m_intVal); // accessing via member
SomeFuncUsingIntValB(fooDot.m_intVal); // accessing via member
SomeFuncUsingIntValC(fooDot.m_intVal); // accessing via member
// Is this better?
int valAsMember = foo.m_intVal;
SomeFuncUsingIntValA(valAsMember);
SomeFuncUsingIntValB(valAsMember);
SomeFuncUsingIntValC(valAsMember);
}
好的,所以我试着在这里找到答案。
简言之:你绝对不需要这么做。
长版本:您可能需要这样做。
因此,在像Javascript
这样的解释程序中,这类事情可能会产生明显的影响。在编译过的程序中,比如C++,并没有到完全不编译的地步。
大多数时候,你不需要担心这些事情,因为编译器优化算法(和实际实现)已经投入了大量资源,编译器将正确地决定该做什么:分配一个额外的寄存器并保存结果,以便重用它,或者每次重新计算并保存寄存器空间,等等
有些情况下编译器无法做到这一点。也就是说,它不能证明多个调用产生相同的结果。然后它别无选择,只能打所有的电话。
现在让我们假设编译器做出了错误的选择,作为预防措施,您需要进行微观优化。您进行了优化,并在这部分代码上实现了10%的性能提升(对于这种优化来说,这已经是一个过于乐观的数字)。但是,你知道吗,你的代码只在这部分代码中花费了1%的时间。剩下的时间很可能花在一些热循环中,等待数据提取。因此,您花费了不可忽略的精力来优化代码,但总时间的性能提高了0.1%,这甚至是不可观察的,因为外部因素会使执行时间的变化远远超过这个数量。
因此,不要花时间在C++中进行微观优化。
然而,在某些情况下,你可能需要这样做,甚至更疯狂的事情。但这只是在对代码进行适当的分析之后,这是另一个讨论。
所以,要担心可读性,不要担心微观优化。
这个问题实际上与->
和.
运算符无关,而是与一般的重复表达式有关。的确,大多数现代编译器都足够聪明,可以优化重复计算同一表达式的代码(假设它没有明显的副作用)。
然而,使用显式中间变量通常会使程序可读性更强,因为它显式地暴露了在所有上下文中都应该使用相同值的事实。它暴露了这样一个事实,即您的意图在所有上下文中使用相同的值。
如果您一次又一次地重复使用相同的表达式来生成该值,那么这个事实就不那么明显了。首先,第一眼很难判断这些表达是否真的相同(尤其是当它们很长的时候)。其次,对看似相同的表达进行顺序评估是否会产生相同的结果并不明显。
最后,通过使用中间变量将长表达式分割成更小的表达式,可以在逐步调试器中简单地调试代码,因为它通过"逐步执行"answers"逐步结束"命令为用户提供了更大程度的控制。
在可读性和可维护性方面,有这样的临时变量肯定会更好。
就性能而言,您不必担心现阶段的这种微观优化(过早优化)。此外,现代C++编译器无论如何都可以优化它,所以你真的不必担心它
- 为什么比较运算符如此快速
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 增量运算符与后缀混淆
- 一个关于在C++中重载布尔运算符的问题
- 运算符C++ "delete []"仅删除 2 个前值
- 模板类无法识别友元运算符
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 关闭||运算符优化
- 通过继承类使用来自不同命名空间的运算符
- C++Cast运算符过载
- 如何使用AngelScript注册SFML Vector2运算符
- 重载元组索引运算符-C++
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 布尔比较运算符是如何在C++中工作的
- 重载运算符new[]的行为取决于析构函数
- 是否需要使用 - &gt;运算符在C 中调用成员函数时