That might sound a little extreme, but in the past 5 years I've run into exactly 1 problem that was solved by busting out the profiler and optimizing. In that same time, I can't count on all my digits the number of features that didn't ship, estimates that were overshot, deadlines that were slipped, etc etc. I've even been part of a team that ran out of runway while popping open jsPerf to choose between !! and Boolean(). Our app was fast as hell -- too bad no one will ever get to use it.
If you're expending cycles choosing between ++x and x++ and you're not ahead of schedule, please stop.
Sorry to hear about your unsuccessful projects, that's a bummer. I hope that premature optimization wasn't a major part of the blame for any of them.
Writing unreadable, micro-optimised code in the name of performance without even attempting to profile it first is another matter.
My personal rule (as a not-very-good hobbyist) is that if I have to refactor everything in order to accommodate an optimisation in a path that's already 'fast enough', or introduce some arcane hackery that only makes sense with comments into otherwise clean code, then it must be backed up with realistic benchmarks (and show a significant improvement).
I chose that example because it didn't need a full paragraph to explain, but you're right that there are probably better ones. Edit: maybe a Python example? ''.join([a, b, c]) is faster than a + b + c, but again 99% of the time you won't be using it in performance critical code. But it's a useful idiom to know.
It’s only if you plan to concatenate a whole lot of strings that join is a clear winner.
My rule of thumb is if you haven't profiled it, it's premature to try and optimize it.
> but sometimes it's nice to make a habit of doing things the faster way when you have two choices that are otherwise indistinguishable.
Now this is a good habit to be in.
The context was specifically about questions on StackOverflow. You don't know if the person asking the question has profiled it or not, and the assumption is often that they haven't. Probably true more often than not, but very condescending and unhelpful to the person who has.
++x can be slower, depending on the context -- it introduces a sequence point.
99% of the time I don't need to worry about the profiler.
I think 100% of time is closer to truth, unless you're using ancient or embedded 8/16-bit compilers.
[1] https://en.wikipedia.org/wiki/Increment_and_decrement_operat...
Wow, B. A blast from the past, sort of. I had read a good book about BCPL (the ancestor to B) many years ago. IIRC, it was by Martin Richards, inventor of BCPL. Pretty interesting book and language. BCPL and B were both typeless languages, or languages with just one type, the machine word (16 or 32 bits, don't remember). Still I found that many algorithms and programs were expressed rather compactly in BCPL - or so it seemed to me at the time. Was quite junior then, and without exposure to more advanced programming languages - only knew BASIC and Pascal, probably; even C, I only learned a bit later.
https://en.wikipedia.org/wiki/B_(programming_language)
https://en.wikipedia.org/wiki/BCPL
https://en.wikipedia.org/wiki/Martin_Richards_(computer_scie...
Also just saw some other interesting stuff from the BCPL article above:
[ BCPL is the language in which the original hello world program was written.[3] The first MUD was also written in BCPL (MUD1).
Several operating systems were written partially or wholly in BCPL (for example, TRIPOS and the earliest versions of AmigaDOS).
BCPL was also the initial language used in the seminal Xerox PARC Alto project, the first modern personal computer; among other projects, the Bravo document preparation system was written in BCPL. ]
Even for the following trivial function:
#include <vector>
#include <string>
std::size_t foo(const std::vector<std::string>& vec)
{
std::size_t n = 0;
for(auto it = vec.begin(), end = vec.end(); it != end; ++it)
{
n += vec.size();
}
return n;
}
MSVC 2017 generates different assembly for ++it vs it++, at the highest optimization level.Hopefully MSVC will improve soon.
Just tried gcc 7.1, both post and pre-increment compile identically.
std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::operator++, COMDAT PROC
mov rax, QWORD PTR [rcx]
mov QWORD PTR [rdx], rax
add rax, 32 ; 00000020H
mov QWORD PTR [rcx], rax
mov rax, rdx
ret 0
For the ++it case: std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::operator++, COMDAT PROC
add QWORD PTR [rcx], 32 ; 00000020H
mov rax, rcx
retThat considered, both pre- and post-increment generate identical code, even with VS2017.
This matches my previous experience about pretty much any compiler in last 15 years or so -- there's no difference between ++i and i++, unless, of course, it's in a statement and changes the actual meaning of code.
"it++" case. Note that iterator function is not called.
foo PROC
mov rdx, QWORD PTR [rcx]
xor eax, eax
mov rcx, QWORD PTR [rcx+8]
cmp rdx, rcx
je SHORT $LN70@foo
mov r8, rcx
sub r8, rdx
sar r8, 5
npad 8
$LL4@foo:
add rax, r8
add rdx, 32 ; 00000020H
cmp rdx, rcx
jne SHORT $LL4@foo
$LN70@foo:
ret 0
foo ENDP
Here's the code generated for "++it" case. Iterator function is not called here either. foo PROC
mov rdx, QWORD PTR [rcx]
xor eax, eax
mov rcx, QWORD PTR [rcx+8]
cmp rdx, rcx
je SHORT $LN68@foo
mov r8, rcx
sub r8, rdx
sar r8, 5
npad 8
$LL4@foo:
add rax, r8
add rdx, 32 ; 00000020H
cmp rdx, rcx
jne SHORT $LL4@foo
$LN68@foo:
ret 0
foo ENDPThat is virtually never the case.
> For example I try to use ++x instead of x++
Those have wildly different semantics.
Those `++` and `--` operators are something to avoid anyway.