-4

I was wondering if the increment and decrement operators ( ++ -- ) have more purpose to it than its plain use to make the code more simple

maybe:

i++;

is more efficient than:

i = i + 1;

?

alfalfa
  • 147
  • 1
  • 8

9 Answers9

2

In many ways, the main purpose of the operators is backwards compatibility. When C++ was being designed, the general rule was to do what C did, at least for non-class types; if C hadn't had ++ and --, I doubt C++ would have them.

Which, of course, begs the question. It's inconceivable that they would generate different code in a modern compiler, and it's fairly inconceivable that the committee would introduce them for optimization reasons (although you never know—move semantics were introduced mainly for optimization reasons). But back in the mid-1970s, in the formative years of C? It was generally believed, at the time, that they were introduced because they corresponded to machine instructions on the PDP-11. On the other hand, they were already present in B. C acquired them from B. And B was an interpreted language, so there was no issue of them corresponding to machine instructions. My own suspicion, which applies to many of the operators (&, rather than and, etc.) is that they were introduced because development at the time was largely on teletypes (tty's), and every character you output to a teletype made a lot of unpleasant noise. So the less characters you needed, the better.

As to the choice between ++ i;, i += 1; and i = i + 1;: there is a decided advantage to not having to repeat the i (which can, of course, be a more or less complex expression), so you want at least i += 1;. Python stops there, if for no other reason than it treats assignment as a statement, rather than as the side effect of an arbitrary expression. With over 30 years of programming in C and C++ under my belt, I still feel that ++ i is missing when programming in Python, even though I pretty much restrict myself in C++ to treating assignment as a statement (and don't embed ++ i in more complicated expressions).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 1
    "B was an interpreted language, so there was no issue of them corresponding to machine instructions" -- doesn't *necessarily* follow. I wasn't around at the time ofc, but Ritchie's "Development of the C language" claims that only the "earliest versions" of B were not compiled. Can you rule out that B was designed with an eye to compilation even though the first implementation wasn't compiled? – Steve Jessop Mar 02 '13 at 13:16
1

The two examples you gave will almost certainly compile to exactly the same machine code. Compilers are very smart. Understand that a compiler rarely executes the code you actually wrote. It will twist it and mould it to improve performance. Any modern compiler will know that i++; and i = i + 1; are identical (for an arithmetic type) and generate the same output.

However, there is a good reason to have both, other than just code readability. Conceptually, incrementing a value many times and adding to a value are different operations - they are only the same here because you are adding 1. An addition, such as x + 3, is a single operation, whereas doing ++++++x represents three individual operations with the same effect. Of course, a smart compiler will also know that for an object of arithmetic type, x, it can do N increments in constant time just by doing x + N.

However, the compiler can't make this assumption if x is of class type with an overloaded operator+ and operator++. These two operators may do entirely different things. In addition, implementing an operator+ as a non-constant time operation would give the wrong impression.

The importance of having both becomes clear when we're dealing with iterators. Only Random Access Iterators support addition and subtraction. For example, a standard raw pointer is a random access iterator because you can do ptr + 5 and get a pointer to the 5th object along. However, all other types of iterators (bidirectional, forward, input) do not support this - you can only increment them (and decrement a bidirectional iterator). To get to the 5th element along with a bidirectional iterator, you need to do ++ five times. That's because an addition represents a constant time operation but many iterators simply cannot traverse in constant time. Forcing multiple increments shows that it's not a constant time operation.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • You could argue the point about incrementing and adding a value being different. And of course, using `++` to advance an iterator, rather than a member function, is really a case of operator overloading abuse. But it is an explication of the difference in modern C++. Which doesn't explain the original motivation: C++ has `++` because C has `++` because B had `++`. And the iterator argument certainly doesn't hold for B. – James Kanze Mar 02 '13 at 12:59
  • @JamesKanze I suppose I wasn't thinking about where `++` came from. I haven't given the reason we have it in the first place, just an explanation for why it is handy to have it now. – Joseph Mansfield Mar 02 '13 at 13:02
  • I'm not sure I agree that "increment" and "add 1" are conceptually different. – Oliver Charlesworth Mar 02 '13 at 13:14
  • @OliCharlesworth I mean "incrementing many times" and "adding" are conceptually different. – Joseph Mansfield Mar 02 '13 at 13:16
1

Performance depends on the type of i.

If it's a built-in type, then optimizers will "notice" that your two statements are the same, and emit the same code for both.

Since you used post-increment (and ignoring your semi-colons), the two expressions have different values even when i is a built-in type. The value of i++ is the old value, the value of i = i + 1 is the new value. So, if you write:

j = i++;
k = (i = i + 1);

then the two are now different, and the same code will not be emitted for both.

Since the post-condition of post-increment is the same as pre-increment, you could well say that the primary purpose of the post-increment operator is that it evaluates to a different value. Regardless of performance, it makes the language more expressive.

If i has class type with overloaded operators then it might not be so simple. In theory the two might not even have the same result, but assuming "sensible" operators i + 1 returns a new instance of the class, which is then move-assigned (in C++11 if the type has a move assignment operator) or copy-assigned (in C++03) to i. There's no guarantee that the optimizer can make this as efficient as what operator++ does, especially if the operator overload definitions are off in another translation unit.

Some types have operator++ but not operator+, for example std::list<T>::iterator. That's not the reason ++ exists, though, since it existed in C and C has no types with ++ but not +. It is a way that C++ has taken advantage of it existing.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • If you write `k = (i = i + 1);`, you have undefined behavior. (`j = i ++;` is just obfuscation.) – James Kanze Mar 02 '13 at 13:10
  • Re your last paragraph, the fact that someone could abuse the operator, and use `++` for the unrelated action of advancing an iterator, isn't really an argument for having `++`. – James Kanze Mar 02 '13 at 13:12
  • 1
    @JamesKanze: (a) why is it UB? (b) I disagree that using `++` to mean generically "increment" as opposed to `+=1` is operator abuse, but I think that's pretty much wholly subjective. I think one can (subjectively) argue that overloading arithmetic operators is always operator abuse unless implementing a numeric type, but personally I am happy for anything that models a finite or infinite Peano-like system to use `++`, anything that models a ring to use `+` or `*`, etc. I do agree (and I explicitly state) that it is not the reason `++` was introduced. – Steve Jessop Mar 02 '13 at 13:18
  • 1
    @JamesKanze: why does 5.17/1 not save me from UB? "the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression". So the read from `i` to establish the value of `k` is sequenced after the assignment to `i`. – Steve Jessop Mar 02 '13 at 13:27
  • My mistake on the undefined behavior. I'm so used to seeing things like `i = ++ i` embedded in further expressions. Things like `k = (i = i + 1)` are fully legal (and regretfully, even used). – James Kanze Mar 02 '13 at 13:50
  • With regards to operator overload abuse: I tend to be very conservative in this respect, and I can sort of see an argument both ways here. (But an iterator supporting `i.next()`, `i.isDone()`, and `i.current()` or `i.element()` is much more natural and expressive.) – James Kanze Mar 02 '13 at 13:53
  • @JamesKanze: if we're reinventing iterators, can those things be member functions that are called by the default implementation of a template free function? So that we can continue using pointers as iterators. – Steve Jessop Mar 02 '13 at 17:21
  • No, but what does it matter? We could easily wrap pointers in an iterator, and use them that way. – James Kanze Mar 03 '13 at 16:40
0

Both would produce same machine instruction(s) in optimized code by a decent compiler.

If the compiler sees i++ is more efficient,then it will convert i=i+1 to i++, or vice-versa. The result will be same no matter what you write.

I prefer ++i . I never write i=i+1.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • I think the OP presented the question in a misleading fashion. `i = i + 1;` requires specifying `i` twice; not an issue for `i`, but `i` can be an arbitrary expression. (And if you write `f() = f() + 1;`, rather than `++ f();`, the compiler must call `f` twice, unless it can "see into" `f`.) The real issue is `++ i;` vs. `i += 1;`. – James Kanze Mar 02 '13 at 13:03
  • The fact that I accidentally hit Enter before finishing the comment:-). Without my subsequent edit, it doesn't make sense. – James Kanze Mar 02 '13 at 13:06
  • @JamesKanze: In my answer, I assumed `i` is one of the built-in types. – Nawaz Mar 02 '13 at 13:10
0

No, it is simply to make typing simple, and to get simpler looking syntax.

When they are both compiled, they are reduced to the same compiled code, and run at the same speed.

sharp12345
  • 4,420
  • 3
  • 22
  • 38
0
  1. The ++ or -- operator allows it to be combined into other statements rather than i=i+1. For e.g. while (i++ < 10) allows a while loop check and an increment to be done after it. It's not possible to do that with i=i+1.

  2. The ++ or -- operator can be overloaded in other classes to have other meanings or to do increments and decrements with additional actions. Please see this page for more info.

ruben2020
  • 1,549
  • 14
  • 24
  • It *is* possible, if somewhat ugly and possibly inefficient, to model the semantics of post-increment `i++` without that operator: `while ((i=i+1,i-1) < 10)`. – us2012 Mar 02 '13 at 12:54
  • Re 1. The language allows it, but I think most programmers have outgrown things like `while ( *dst++ = *src++ );`. It was already recognized as bad practice when K&R wrote the first "Programming in C". – James Kanze Mar 02 '13 at 13:08
  • Re. It's true that you can overload `++` to do something totally unrelated to adding one, but that's generally considered operator overloading abuse. – James Kanze Mar 02 '13 at 13:09
  • I think using `++` like `while (i++ < 10)` is not bad practice, but doing `while ( *dst++ = *src++ )` certainly is. With operator overloading, you could do for example the following. I define a class which keeps an integer value and the min and max value can be defined as constructor arguments, say 0 and 100. Now I overload the `--` and `++` operators so that it does decrement and increment only if the new value is within the range of 0 and 100. So if the value of `x` is 100 and you do `x++`, it will stay at 100. I don't consider this abuse, but a very specific design for a specific need. – ruben2020 Mar 02 '13 at 13:16
0

They both are not exactly same , though functionally they are same, there is a difference in precedencei++ has more precedence(more priority) than i=i+1

Vinod Paul
  • 359
  • 2
  • 14
0

Try to replace ++i or i++ in some more complicated expression. You're going to have difficulties with the preincrement/postincrement feature. You're going to need to split the expression into multiple ones. It's like ternary operator. It is equivalent, the compiler may perform some optimizations regardless on the way you enter the code, but ternary operator and preincrement/postincrement syntax just save you space and readability of the code.

V-X
  • 2,979
  • 18
  • 28
  • "You're going to need to split the expression into multiple ones." Sounds more like an argument against `++` to me. Embedding changes of state in the middle of a complex expression is mainly an obfuscation technique, avoided by serious programmers. – James Kanze Mar 02 '13 at 13:02
  • Of cause. That's why you have to think, during development, instead of having some general answer like "++ operator is bad": it has it's use and it shouldn't be used, when the code could be hard readable. Imagine, someone will start using `for (i = 0; i < 10; i = i + 1)` - that's ridiculous. – V-X Mar 02 '13 at 13:10
0

The difference between i++ and i = i + 1 is that the first expression only evaluates i once and the second evaluates it twice. Consider:

int& f() {
    static int value = 0;
    std::cout << "f() called\n";
    return value;

}

f()++;         // writes the message once
f() = f() + 1; // writes the message twice

And if f() returns different references on different calls, the two expressions have vastly different effects. Not that this is good design, of course...

Pete Becker
  • 74,985
  • 8
  • 76
  • 165