C++中的增量 - 何时使用x ++或++ x?

Jes*_*ond 83 c++ pre-increment post-increment

我目前正在学习C++,而且我刚刚学会了增量.我知道你可以使用"++ x"进行增量,然后使用"x ++"进行增量.

不过,我真的不知道何时使用两者中的任何一个...我从来没有真正使用过"++ x",到目前为止,事情总是很好 - 所以,我什么时候应该使用它?

示例:在for循环中,何时优先使用"++ x"?

此外,有人可以确切地解释不同的增量(或减量)如何工作?我真的很感激.

Oli*_*ich 101

这不是偏好问题,而是逻辑问题.

x++处理当前语句递增变量x的值.

++x处理当前语句之前递增变量x的值.

所以只需决定你写的逻辑.

x += ++i将增加i并将i + 1添加到x. x += i++将i添加到x,然后递增i.

  • 请注意,在for循环中,在primatives上,绝对没有区别.许多编码风格将建议永远不要使用增量运算符,否则可能会被误解; 也就是说,x ++或++ x应该只存在于它自己的行上,而不是y = x ++.就个人而言,我不喜欢这样,但这种情况并不常见 (22认同)
  • 这可能看起来像是迂腐(主要是因为它:))但是在C++中,`x ++`是一个在增量前具有值'x'的右值,`x ++`是一个增值后值为'x`的左值.当实际递增的值存储回x时,两个表达式都不保证,只保证它在下一个序列点之前发生."处理当前语句后"并不严格准确,因为某些表达式具有序列点,而某些语句是复合语句. (14认同)
  • 实际上,答案是误导性的.变量x被修改的时间点在实践中可能没有差异.区别在于x ++被定义为返回前一个x值的右值,而++ x仍然是指变量x. (10认同)
  • @BeowulfOF:答案意味着一个不存在的订单.标准中没有任何内容可以说明增量何时发生.编译器有权将"x + = i ++"实现为:int j = i; i = i + 1; x + = j;"(即'i'在"处理当前语句"之前递增).这就是为什么"i = i ++"具有未定义的行为以及为什么我认为答案需要"调整"的原因."x的描述" + = ++ i"是正确的,因为没有关于命令的建议:"将递增i并将i + 1添加到x". (5认同)
  • 如果在它自己的行上使用,生成的代码几乎肯定是相同的. (2认同)

duf*_*ymo 47

斯科特迈耶斯告诉你更喜欢前缀,除非那些逻辑会指示后缀是合适的.

"更有效的C++"第6项 - 这对我来说是足够的权威.

对于那些没有这本书的人,这里有相关的引用.从第32页开始:

从你作为C程序员的日子开始,你可能会记得增量运算符的前缀形式有时被称为"增量和提取",而后缀形式通常被称为"提取和增量".这两个短语很重要,因为它们都可以作为正式的规范......

在第34页:

如果你是那种担心效率的人,那么当你第一次看到后缀增量功能时,你可能会耿耿于怀.该函数必须为其返回值创建一个临时对象,上面的实现还会创建一个必须构造和销毁的显式临时对象.前缀增量功能没有这样的临时...

  • 我碰巧用gcc测试了这个:在一个for循环中,在执行`i ++`或`++ i`后抛出该值,生成的代码是相同的. (7认同)
  • 如果编译器没有意识到增量之前的值是unnessescary,它可能会在几条指令中实现后缀增量 - 复制旧值,然后递增.前缀增量应始终只是一条指令. (4认同)
  • 您可以放心使用Scott Meyers,但如果您的代码非常依赖于性能,以至于++ x和x ++之间的任何性能差异实际上都很重要,那么实际上使用可以完全,无论上下文如何,都可以适当地优化两个版本。“由于我使用的是这把破烂的旧锤子,所以我只能以43.7度的角度打入钉子”对于通过仅以43.7度的角度打入钉子来建造房屋,这是一个糟糕的论点。使用更好的工具。 (2认同)

Phi*_*gan 23

从递增迭代器时的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   }
Run Code Online (Sandbox Code Playgroud)

显然,它比预增量效率低.

预增量不会生成临时对象.如果您的对象创建成本很高,这可能会产生显着差异.


chu*_*hub 7

我只是想注意,如果使用前/后增量,其中语义(前/后)无关紧要,则生成的代码会相同.

例:

pre.cpp:

#include <iostream>

int main()
{
  int i = 13;
  i++;
  for (; i < 42; i++)
    {
      std::cout << i << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

post.cpp:

#include <iostream>

int main()
{

  int i = 13;
  ++i;
  for (; i < 42; ++i)
    {
      std::cout << i << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

_

$> g++ -S pre.cpp
$> g++ -S post.cpp
$> diff pre.s post.s   
1c1
<   .file   "pre.cpp"
---
>   .file   "post.cpp"
Run Code Online (Sandbox Code Playgroud)

  • 对于像整数这样的原始类型,是的.你有没有检查过看看`std :: map :: iterator`之类的差异?当然有两个运算符是不同的,但我很好奇编译器是否会在不使用结果的情况下优化后缀为前缀.我不认为这是允许的 - 因为后缀版本可能包含副作用. (5认同)

rmn*_*rmn 6

要记住,最重要的是imo,x ++需要在增量实际发生之前返回值 - 因此,它必须制作对象的临时副本(预增量).这不如++ x有效,后者在原位递增并返回.

另外值得一提的是,大多数编译器都能够在可能的情况下优化这些不必要的东西,例如两个选项都会导致相同的代码:

for (int i(0);i<10;++i)
for (int i(0);i<10;i++)
Run Code Online (Sandbox Code Playgroud)


Bid*_*ids 5

我同意@BeowulfOF,但为了清楚起见,我始终主张拆分语句,以便逻辑绝对清晰,即:

i++;
x += i;
Run Code Online (Sandbox Code Playgroud)

或者

x += i;
i++;
Run Code Online (Sandbox Code Playgroud)

所以我的回答是,如果你编写了清晰的代码,那么这应该很少有关系(如果它很重要,那么你的代码可能不够清晰)。


小智 5

如果count{5};

如果您使用 ++count 它将在语句之前处理

total = --count +6;
Run Code Online (Sandbox Code Playgroud)

总计将等于 10

如果使用 count++ 它将在语句之后处理

total = count-- +6;
Run Code Online (Sandbox Code Playgroud)

总计将等于 11

  • Total = --count + 6 相当于 count = count - 1;total = count+6; 而total = count-- + 6 相当于total = count + 6;计数 = 计数 - 1;语句的顺序不同,结果也不同。 (2认同)