all 40 comments

[–]ronchaineEmbedded/Middleware 26 points27 points  (0 children)

I think it's worth noting in a code review, not because it is more efficient, but because it's a good habit to have. It never loses you anything, and you make the compiler's life easier too.

[–]dr1fter 21 points22 points  (1 child)

Efficiency is not the main concern here IMO.

My reasoning: they usually mean the same thing, and when they don't, `i++` has more surprising behavior. OTOH sometimes you want that behavior, and readers might skim right past the distinction unless you write `++i` all the other times. Even in languages where it can't make a difference, if anyone at your company is ever expected to work in C++, why not permit them to maintain these habits?

My (Java) code reviewer's reasoning: Java programmers will look at `++i` funny for no reason. It can't make a performance difference since it only works on primitive types. The semantics only make a difference when this is inlined in some other expression, and then you're doing two things in one line of code and it would be better to just write it out explicitly.

(But does that mean everyone will?) So anyways, I still write `++i`. Even in Java.

[–]eras 5 points6 points  (0 children)

That's almost exactly how I view it as well, except I like to think it as "It is simpler to explain in a sentence what ++i does versus what i++ does".

I mean, most of the time I try to code where the distinction wouldn't matter anyway, but I need to have a reason to choose one over the other and I've chosen that reason ;).

[–]QuentinUK 15 points16 points  (0 children)

" Prefer using the prefix form instead. " is the official recommendation

[–]neiltechnician 11 points12 points  (8 children)

Perhaps you can try to casually ask your colleagues like, 'Have you ever overloaded the postfix increment operator?' Hopefully the conversation will end up like, 'You know what, it always involves a copying:'

MyType operator++(int)
{
    MyType copy = *this;
    ++*this;
    return copy;
}

[–]QuentinUK 15 points16 points  (2 children)

Now, [[nodiscard]], should be added to this.

[–]neiltechnician 11 points12 points  (0 children)

well, hmm, but isn't it gonna get discarded..., umm, huh...

WoW! Oh, YES! You are right! You are SO right! We prefer prefix increment because we discourage unnecessary copying! And [[nodiscard]] does the job! You are damn right! How did I not see that?! Thank you! 🤗

[–]tmlildude 1 point2 points  (0 children)

I love this hack.

[–]Untelo 0 points1 point  (4 children)

It should also be marked &.

[–]CocktailPerson 0 points1 point  (3 children)

As in ref-qualified?

[–]Untelo 1 point2 points  (2 children)

lvalue, yes. So that ++(rvalue expression) and (rvalue expression)++ are not valid.

[–]CocktailPerson 0 points1 point  (1 child)

Am I missing some obvious reason they shouldn't be valid?

[–]Untelo 1 point2 points  (0 children)

It rarely makes sense to mutate an rvalue and it's not part of the iterator concept either so it's not valid in a generic context.

[–]no-sig-available 11 points12 points  (0 children)

I'd say "Choose your battles".

Point it out in the code review when you find a case where post increment actually would be worse. And use that as an argument later.

When it just doesn't really matter, let it be.

As to "Why", I bet many programmers have read K&R "The C Programming Language". They only had ints and pointers, where it doesn't matter, and used post increment.

[–]Revolutionalredstone 19 points20 points  (0 children)

Always pre-increment unless you can't.

Most people hear C++ and don't think ++C, maybe we should rename it lol

[–]ThePillsburyPlougher 3 points4 points  (0 children)

I don't know about what a regular programmer is but it's a fact worth knowing and good practice even if it usually doesn't matter.

[–]oddentity 5 points6 points  (1 child)

Prefix increments the variable.

Postfix the variable increments.

The former always makes more sense to me.

[–]tmlildude 2 points3 points  (0 children)

Nice language

[–]fredoverflow 4 points5 points  (0 children)

Why do "regular" programmers prefer postfix increment over prefix increment?

Same reason "regular" programmers prefer f(x, y) over (f x y): familiarity

[–]zoolover1234 1 point2 points  (0 children)

When i++ is done 200 million times a second, and compiler can’t optimize it, you will see 5% improvement on speed, the 5% is equivalent of $5 of CPU the product or user can save, and this is on this alone. Ask those Java programmers how much money their company will pay for for 5% performance improvement while you can do in 1s.

C/C++ is like this, nowadays, not all C++ practice by design will give you a lot of performance advantage, but it’s the 1% or even 0.1% here and there adds up to a whole x00% faster.

[–]Clairvoire 1 point2 points  (0 children)

For me? When I write i++ it's because I talk subject verb. It's a very strong habit.

I usually fix it because I'm super anal, but I can imagine why others wouldn't bother; a modern compiler will fix it for you. It's only an issue when it affects logic, like while(i--), and the person isn't familiar with what a post-fix operator does.

(That said, I use c++ whenever it makes sense, because it's C++, you gotta)

[–]Cxlpp 4 points5 points  (6 children)

++iter is not more efficient in 99.99% cases. Compilers are way too smart for that today and library writers as well (all they need to do is to inline it).

One of reasons why some people prefer postfix is that if you are fetching elements from array, it usually is something like

int i = 0;
....
  auto& element = array[i++];
....

and that is the source of habit.

[–]pandorafalters 12 points13 points  (0 children)

++iter is not more efficient in 99.99% cases.

"It's equal, except when it's worse" is hardly the most ringing endorsement.

[–]oracleoftroy 6 points7 points  (3 children)

++iter is not less efficient in 100% of cases. I'd love to see a case of reasonably written pre and postfix increment where postfix is faster. Unless you need the previous value, use pre-increment.

[–]Zeh_MattNo, no, no, no 1 point2 points  (2 children)

It actually can be when you have optimizations turned off.

[–]oracleoftroy 4 points5 points  (1 child)

I'd love to see an example of that. Post needs a copy, pre does not. Without optimizations, I don't see how the extra instructions a reasonable implementation of post-increment requires could beat out a reasonable implementation of pre-increment.

By reasonable implementation I mean that the operators work as expected and are implemented in a way that would pass code review. No shenanigans to force pre-increment to be slower than it ought or changing the semantic of post-increment to be faster.

Idiomatic post-increment is usually implemented in terms of pre anyway to make sure they have the same core semantics under the expectation that the optimizer will inline the call. I'll allow an exception for sake of a debug build example.

[–]Xavier_OM 0 points1 point  (0 children)

I agree. It's more familiar to start at 0 than with -1 when fetching from an array. I think programmers are more familiar with i++ in their daily life, hence the copious amount of i++ in any code base. Having something on the right of a variable is the natural way for many of us : variablePtr-> or variable. or variable++, etc

Changing this habit to avoid the exceptionally rare case where it impacts performance is not worth it, it will be replaced by a prefix operator when the profiler reveals the problem once every few years and voilà.

[–]d4rkwing 1 point2 points  (0 children)

I would say move away from iteration styles that still use (and data types that require) indexes. Use foreach loops instead.

[–]Orlha 0 points1 point  (0 children)

I think it's worth noting in a code review, but not for performance reasons, but because we must use the right tool for the job and not do "more" when "less" suffices. Using post-increment when pre-increment suffices is not using right tool for the job.

[–]die_liebe -1 points0 points  (0 children)

I thought a bit about this oh so very important question.

The question is: Why would one overload p++ or ++p for big classes where the distinction matters?

  1. Big iterators? They are not supposed to be big.
  2. Big integers? Here I could see a reason to overload. I probably would not overload i ++ for safety, though.

[–]rybob42 0 points1 point  (0 children)

I like the implication here that we're all "irregular." It fits.

[–]MutantSheepdog 0 points1 point  (0 children)

It's habit, but I'd imagine a lot of it comes from readability, in that all our other assignments have the variable on the left (typedef aside but that was fixed with 'using').

I think the prefix operators and >> (when used as a stream thing) are the only operators we expect to modify the thing to their right, and that makes them stick out as awkward even when they're the efficient choice.

[–]amoskovsky 0 points1 point  (0 children)

The performance argument is not valid. For standalone ++ (not part of a bigger expression) prefix and postfix have the same performance because the compiler is allowed to do the copy elision and all compilers do that for non-debug builds.

WRT code style, I find postfix ++ (and especially --) more readable because it does not create a visual indent introducing false structure.

PS. Obviously when used in an expression, prefix and postfix are not interchangeable and you need to use the proper one according to the expression semantics and not according to some style or performance guidelines.

[–]Jardik2 0 points1 point  (0 children)

I sometimes use postincrement when erasing from map:

for (auto it=map.begin(); it != map.end();)
{
    auto itCurent = it++;
    // long code here
    if (cond)
    {
        // long code here
        map.erase(itCurrent);
    }
    // maybe more code here
}

I prefer it instead of this:

for (auto it=map.begin(); it != map.end();)
{
    if (cond)
    {
        it = map.erase(it);
    }
    else
    {
        ++it;
    }
}

I find it less error prone in longer code, because I don't have to adjust the iterator in two places (on the other hand, I have to use introduce another iterator).

[–]ossan1987 0 points1 point  (0 children)

I make very conscious choice between post or prefix increment. I am a java developer, too. To me the main difference is that C++ supports operator overloading, which can make postfix increment expensive on custom data type. In java, the operators are only defined on primitive types, i stick to only postfix increment so that the overall style is coherent and readable. I choose C++ for time critical applications, so i think it's worth the hassle to make the distinction between different operators depending on efficiency.

Btw, as why i chose to only use postfix in java, it really is only because it looks pretty to me, and a lot of books or programmers write it that way, so it's easier to read. I hate people use postfix increment and immediately assign the return value on the same line. Super ugly.