在C ++中增加 – 何时使用x ++或++ x?
我目前正在学习C ++,而前一段时间我也学习了这个增量。 我知道你可以使用“++ x”来使之前的增量和“x ++”来完成。
不过,我真的不知道什么时候使用这两种…我从来没有真正使用过“++ x”,而且到目前为止,事情一直很好 – 所以,我应该什么时候使用它?
例如:在for循环中,何时最好使用“++ x”?
另外,有人可以解释不同的增量(或递减)是如何工作的? 我真的很感激。
这不是偏好问题,而是逻辑问题。
处理当前语句后 x++
递增variablesx的值。
++x
在处理当前语句之前递增variablesx的值。
所以只要决定你写的逻辑。
x += ++i
将增加i并将i + 1添加到x。 x += i++
将i加到x,然后增加i。
斯科特·迈尔斯(Scott Meyers)告诉你更喜欢前缀(prefix),除非在逻辑上指定后缀是合适的地方。
“更有效的C ++”项目#6 – 这对我来说是足够的权威。
对于那些不拥有这本书的人来说,这里有相关的引语。 从页面32:
从你作为C程序员的日子,你可能会记得增量操作符的前缀forms有时被称为“增量和取”,而后缀forms通常被称为“取和增量”。 这两个短语很重要,因为它们都只是作为正式的规范。
和在页34:
如果你是那种担心效率的人,当你第一次看到后缀增量函数的时候,你可能会大汗淋漓。 该函数必须为其返回值创build一个临时对象,而上面的实现也会创build一个必须构造和销毁的显式临时对象。 前缀增量function没有这样的临时…
从递增迭代器时的cppreference :
如果你不打算使用旧的值,你应该更喜欢pre-increment操作符(++ 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 }
显然,它比预增量效率低。
预增量不会生成临时对象。 如果您的对象创build昂贵,这可以产生显着的差异。
我只是想要注意到,如果你使用前/后增量(pre / post)的语义无关紧要的话,那么代码是相同的。
例:
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"
要记住的最重要的事情是,imo需要在增量实际发生之前返回值 – 因此,它必须创build对象的临时副本(预增量)。 这比++ x更有效,它在原地增加并返回。
另外值得一提的是,大多数编译器可以在可能的情况下优化这些不必要的东西,例如这两个选项都会在这里导致相同的代码:
for (int i(0);i<10;++i) for (int i(0);i<10;i++)
我同意@BeowulfOF,尽pipe为了清楚起见,我总是主张分裂陈述,以便逻辑是绝对清楚的,即:
i++; x += i;
要么
x += i; i++;
所以我的答案是,如果你写清楚的代码,那么这应该很less(如果它很重要,那么你的代码可能不够清楚)。
只是想再次强调,++ x预计会比x ++ 更快 (特别是如果x是某种任意types的对象),所以除非出于逻辑的原因需要使用++ x。
你解释了正确的区别。 这只取决于你是否希望x在每次运行循环之前或之后增加。 这取决于你的程序逻辑,什么是合适的。
处理STL-Iterator(也实现这些操作符)的一个重要区别是,它会创build迭代器指向的对象的副本,然后递增,然后返回副本。 ++另一方面先执行增量,然后返回对迭代器现在指向的对象的引用。 当性能的每一点都计数或者当你实现你自己的STL迭代器时,这大部分是相关的。
编辑:修正前缀和后缀符号的混合
在考虑代码的清晰度时,理解语言的语法很重要。 考虑复制一个string,例如后增加:
char a[256] = "Hello world!"; char b[256]; int i = 0; do { b[i] = a[i]; } while (a[i++]);
我们希望循环通过遇到string末尾的零字符(它testing错误)来执行。 这就要求testing值的预增量和增加索引。 但不一定按照这种顺序 – 用预增量编码的方法是:
int i = -1; do { ++i; b[i] = a[i]; } while (a[i]);
这是一个味道更清楚的问题,如果机器有一个寄存器,那么即使一个[i]是一个昂贵的或有副作用的函数,它们也应该有相同的执行时间。 指数的退出价值可能有显着差异。
++的后缀forms, – 运算符遵循规则use-then-change ,
前缀forms(++ x, – x)遵循规则更改 – 然后使用 。
例1:
当多个值与<<使用cout级联时,则计算(如果有的话)从右到左发生,但打印从左到右发生,例如(如果val最初是10)
cout<< ++val<<" "<< val++<<" "<< val;
将导致进入
12 10 10
例2:
在Turbo C ++中,如果在expression式中发现多个++或(以任何forms),则首先计算所有前缀forms,然后计算expression式,最后计算后缀forms,
int a=10,b; b=a++ + ++a + ++a + a; cout<<b<<a<<endl;
这是在Turbo C ++的输出
48 13
而现代编译器将输出(因为他们严格遵守规则)
45 13
- 注:不build议在一个expression式中多次使用相同variables的递增/递减运算符。 这样的处理/结果
expression式因编译器而异。