我目前正在学习C ++,不久前我已经了解了增量。我知道您可以使用“ ++ x”在之前进行增量,然后使用“ x ++”在之后进行增量。
不过,我真的不知道什么时候使用这两种方法中的任何一种...我从来没有真正使用过“ ++ x”,并且到目前为止一切正常,因此,我什么时候应该使用它?
示例:在for循环中,何时最好使用“ ++ x”?
另外,有人可以确切解释不同的增量(或减量)如何工作吗?我真的很感激。
我目前正在学习C ++,不久前我已经了解了增量。我知道您可以使用“ ++ x”在之前进行增量,然后使用“ x ++”在之后进行增量。
不过,我真的不知道什么时候使用这两种方法中的任何一种...我从来没有真正使用过“ ++ x”,并且到目前为止一切正常,因此,我什么时候应该使用它?
示例:在for循环中,何时最好使用“ ++ x”?
另外,有人可以确切解释不同的增量(或减量)如何工作吗?我真的很感激。
Answers:
这不是偏好问题,而是逻辑问题。
x++
处理完当前语句后,递增变量x的值。
++x
在处理当前语句之前递增变量x的值。
因此,只需确定您编写的逻辑即可。
x += ++i
将增加i并将i + 1加到x。
x += i++
将i加到x,然后增加i。
x++
是一个rvalue,其值x
之前为递增,x++
是一个lvalue,其值x
之后为递增。这两个表达式都不能保证将实际的增量值存储回x时,只能保证它出现在下一个序列点之前。“处理当前语句之后”并不是严格准确的,因为某些表达式具有序列点,而某些语句是复合语句。
斯科特·迈耶斯(Scott Meyers)告诉您更喜欢使用前缀,除非在逻辑上需要使用后缀的情况下除外。
“更有效的C ++”第6项 -对我来说已经足够了。
对于那些没有这本书的人,这里是相关的报价。从第32页:
从成为C程序员的那一天开始,您可能会记得,增量运算符的前缀形式有时被称为“增量和获取”,而后缀形式通常被称为“获取和增量”。这两个词很重要,因为它们几乎都是形式规范。
并在第34页上:
如果您是那种担心效率的人,那么当您第一次看到后缀增加功能时,您可能会大汗淋漓。该函数必须为其返回值创建一个临时对象,并且上面的实现还创建了一个必须构造和销毁的显式临时对象。前缀增量功能没有这样的临时对象。
i++
or或之后,该值被丢弃++i
,生成的代码是相同的。
++x
和之间的性能差异都x++
非常重要,那么无论使用哪种版本,无论使用哪种版本,都可以完全,正确地优化任一版本的编译器,这一点更为重要。上下文。“由于我使用的是这把破烂的旧锤子,所以我只能以43.7度的角度打入钉子”对于以仅43.7度的角度打入钉子来建造房屋的说法不佳。使用更好的工具。
从cppreference递增迭代器时:
如果您不打算使用旧值,则应该使用前递增运算符(++ iter)而不是后递增运算符(iter ++)。后增量通常按以下方式实现:
Iter operator++(int) {
Iter tmp(*this); // store the old value in a temporary object
++*this; // call pre-increment
return tmp; // return the old value }
显然,它的效率不如预增量。
预增量不会生成临时对象。如果您的对象创建成本很高,那么这可能会带来很大的不同。
我只是想注意到,如果您使用前置/后置增量(语义(前置/后置)无关紧要),则生成的代码通常是相同的。
例:
pre.cpp:
#include <iostream>
int main()
{
int i = 13;
i++;
for (; i < 42; i++)
{
std::cout << i << std::endl;
}
}
post.cpp:
#include <iostream>
int main()
{
int i = 13;
++i;
for (; i < 42; ++i)
{
std::cout << i << std::endl;
}
}
_
$> g++ -S pre.cpp
$> g++ -S post.cpp
$> diff pre.s post.s
1c1
< .file "pre.cpp"
---
> .file "post.cpp"
std::map::iterator
?当然,这两个运算符是不同的,但是我很好奇,如果不使用结果,编译器是否会将后缀优化为前缀。考虑到后缀版本可能包含副作用,我认为这是不允许的。
只是想再次强调++ x 比x ++ 更快(特别是如果x是任意类型的对象),因此,除非出于逻辑原因需要,否则应使用++ x。
您正确解释了差异。这仅取决于您是否希望x在每次循环之前或之后递增。这取决于您的程序逻辑,什么才是合适的。
处理STL-Iterators(也实现这些运算符)时的一个重要区别是,它++创建迭代器指向的对象的副本,然后递增,然后返回该副本。另一方面,++ it首先执行增量,然后返回对迭代器现在指向的对象的引用。当性能的每一点都很重要或实现自己的STL-iterator时,这才最重要。
编辑:修复了前缀和后缀表示法的混淆
++的后缀形式,-运算符遵循use-then-change规则,
前缀格式(++ x,-x)遵循规则change-then-use。
当使用cout将多个值与<<层叠时,则计算(如果有的话)从右到左进行,但是打印从左到右进行,例如,(如果val最初为10)
cout<< ++val<<" "<< val++<<" "<< val;
将导致
12 10 10
在Turbo C ++中,如果在表达式中发现++或(以任何形式)的多次出现,则首先计算所有前缀形式,然后评估表达式,最后计算后缀形式,例如,
int a=10,b;
b=a++ + ++a + ++a + a;
cout<<b<<a<<endl;
在Turbo C ++中的输出将是
48 13
而现代编译器的输出将是(因为它们严格遵守规则)
45 13
在考虑代码的清晰度时,了解语言语法很重要。考虑复制一个字符串,例如使用后增量:
char a[256] = "Hello world!";
char b[256];
int i = 0;
do {
b[i] = a[i];
} while (a[i++]);
我们希望循环通过在字符串末尾遇到零字符(测试为假)来执行。这需要测试值的预增值以及索引的增值。但不一定按该顺序排序-使用预增量进行编码的方式是:
int i = -1;
do {
++i;
b[i] = a[i];
} while (a[i]);
这是一个更清晰的问题,即使a [i]是一个昂贵的函数或具有副作用,如果该机器具有完整的寄存器,则两个寄存器都应具有相同的执行时间。一个显着的差异可能是索引的退出值。