
Is C++ fast? - AlexeyBrin
https://zeuxcg.org/2019/01/17/is-c-fast/
======
lultimouomo
So if you get rid of bounds check, reimplement your own feature-limited vector
and hash table and _change the algorithm moving from a general purpose exact
sort to an inexact, domain-specific one_ , you can improve your run time from
572ms to 320ms.

What does this have to do with C++?

~~~
throwawaymath
I interpret the title to mean, "Is standard usage of C++ language features and
the STL competitive with C?". The author is basically showing how you improve
performance by selectively tearing out more and more features C++ hands you
out of the box. This is characteristic of writing C++ in a more C-like style.
In that sense I think the author is correct.

However I'd also say this is something already well known by most C and,
particularly, C++ developers. Yes, you can get better performance by
reimplementing much of what C++ gives you, and that is typical of writing C
code instead of C++. But there's a fair bit of productivity trade off in doing
so.

~~~
deng
I'm pretty sure I could make a faster 'printf' but which only supports '%d'.
Does that mean 'C is slow'?

~~~
simias
I'd say that printf, with its own DSL, _is_ actually pretty slow. It's meant
for debugging or "slow" I/O, if you need to write a lot of data it should be
avoided.

A few years ago for debugging purposes I wanted to hexdump a large amount of
data. Turns out that the standard hexdump tool was pretty slow at it, writing
a simple C utility that would format the dump "by hand" instead of using
printf was about an order of magnitude faster. You have fully static code
instead of the interpreted format string, you can unroll all the formatting,
you don't have to rewrite the characters that don't change in every line
(spaces, delimiters etc...). It's lightning fast but of course not very
flexible.

~~~
ghettoimp
It's been a long time since I've done C++. I wonder if

    
    
       int x;
       cout << x;
    

ought to be faster than printf("%d", x), by virtue of knowing the types ahead
of time?

~~~
Someone
Pedantic: No. If you write

    
    
      #include “studio.h”
      int x;
      printf(“%d”, x);
    

the compiler knows the types ahead of time, too, so that cannot explain any
speed difference (and yes, C compilers do try to avoid the generic _printf_ in
the library. See
[http://www.ciselant.de/projects/gcc_printf/gcc_printf.html](http://www.ciselant.de/projects/gcc_printf/gcc_printf.html)
for examples)

(The _#include_ is essential. With it, the compiler can know what _printf_
does, and, in theory, optimize it to a int-to-string conversion and a _puts_
system call. Without it, it cannot, because it doesn’t know what the _printf_
function does (in this case, it is easier to generate fast code for the
compiler if it doesn’t have the source available than when it would see source
code for a function called _printf_ )

Utterly pedantic: no. As given, both are undefined behavior, and it is trivial
for a compiler to discover that.

~~~
tom_mellior
> and yes, C compilers do try to avoid the generic printf in the library

That is true for certain format strings (containing only %s or %c
conversions), but for %d GCC and Clang don't seem to want to call a print_int
function, possibly because there is none:
[https://gcc.godbolt.org/z/rltFse](https://gcc.godbolt.org/z/rltFse)

------
inetknght
I haven't (yet) read the article, but let me provide an anecdote to answer the
question posed by the post title "Is C++ fast?":

I write in C++. I had a coworker who wrote in Ruby. He wanted to learn C++
because C++ is "fast". So he wrote two identical programs: one in C++ and one
in Ruby. Then, he ran both programs though `time` to determine how long each
took.

His C++ program took longer.

Why was that?

He didn't write his C++ program using any efficient algorithms whatsoever
while his Ruby program was well-designed. He came to me to try to tell me that
C++ wasn't as fast as Ruby.

So I rewrote his C++ program. My C++ program then ran almost instantly while
his Ruby program hadn't even begun reading or writing; the C++ program
finished while the Ruby program was still initializing the Ruby runtime
libraries.

Is C++ fast? Yes, it _can_ be. But it's only fast if the developer understands
how to make it fast.

Don't use C++ because it's "fast". Use C++ because you understand what its
intended purpose is: to be close to the hardware.

~~~
grecy
I really like your comment, thanks.

I suppose the question that many people would like to ask, but it's hard to
test is:

"Can we rank the speed of languages, given each are used by a domain expert to
take full advantage of the features of that language"

or some such.

i.e. if a masterful C programmer and a masterful C++ programmer and a
masterful Java Programmer and a masterful Ruby programmer all write something,
which is faster.

I'm sure the answer is "it depends", because that's always the answer.

~~~
jungler
For that particular question: They would all be the same speed because the
optimization requirement would lead each one to write a compiler in their
language of choice that emits a perfectly tuned assembly binary.

What gets overlooked in language performance is that you pick a language for
what are, in essence, placeholder constructs. The performance matters only in
that you need it to be fast enough "off the shelf" that you don't _have_ to
start writing a compiler. But you generally aren't prevented from using that
approach to boost your existing code, and high performance systems often
converge on that strategy in some degree, because it lets you keep
maintainable source code and add toggles for debugging and optimization that
you won't get from treating the application and compiler code as separate
entities.

------
entelechy
> Let’s try to replace the only STL component we’re still using, std::vector,
> with a really simple dynamic array - we don’t need resize or push_back in
> our code, all arrays are initialized with the right size.

Given those requirements, a custom allocator would speed things up. A custom
allocator could allocate even on the stack (small buffer optimisation) if
possible or use a memory pool.

Embracing C++ features or reading the docs often gives you more than going
back to C or reinventing the wheel.

However I think this demonstrates one of the many lurking problems of C++: It
does not enforce the right way of doing things nor makes it easy. Instead it
makes the right solution awkward or cumbersome to write.

~~~
jcelerier
> It does not enforce the right way of doing things nor makes it easy.

but what the author is doing here, while being "the right thing" for his own
project with specific performance requirements, is absolutely not the right
thing to do for the average project that has a few std::vector of 15 widgets,
a dozen strings and six and a half pixmaps, or does the occasional web
request.

~~~
jblow
Why not? How do you know?

~~~
gmueckl
As already said, it depends on the type of project. Sometimes performance is
key, sometimes implementation time is. It is the old tradeoff between
engineering effort spent and the value gained.

------
rwmj
It would be nice if he used a newer version of GCC and a newer base system in
general, rather than the 2+ year old version of Ubuntu. I would also like to
see % change as a column in those tables.

Also I'd like to see other optimization levels, since at least GCC adds a lot
more potentially slow (to compile) optimizations at -O3. Maybe -ffast-math.
Static linking too could conceivably make a difference if he calls into
external libraries frequently.

And where does perf say the time is going? Maybe it's all lost in branches or
cache misses so a different algorithm that branches less or uses denser data
could help.

How about vectorization? I've now looked at the code and it's all vectors,
arrays and matrices so surely this is an application for AVX, maybe even a
GPU.

Anyway I think what's clear is this doesn't have much to do with C vs C++.

------
thestoicattack
The most surprising part of this to me was the speedup from replacing
std::vector.

They write, "We don’t need resize or push_back in our code, all arrays are
initialized with the right size." But if you're not doing any resizing or
anything, and you're reserving the right amount, std::vector basically _is_ a
thin wrapper over a dynamically-allocated raw array -- which is what they tout
as their replacement.

I guess I'm surprised that the overhead from default initialization was so
large.

With vector, it seems there are always tradeoffs: resize and you have some
initialization overhead, but only reserve and you will have a bounds-check-
maybe-realloc every time you need to push_back. Of course, since you reserved,
the realloc never happens, but you still have to check each time.

I wonder if something like generate_n or copy_n into a back_inserter can avoid
the bounds checks?

~~~
jhasse
> std::vector basically is a thin wrapper over a dynamically-allocated raw
> array

Not exactly. A dynamically-allocated array doesn't necessarily save its own
size (the system allocator can do optimizations), but std::vector does (you
could call size() on it). So std::vector has to save this size somewhere,
which takes space and time.

~~~
thestoicattack
For me, the overhead of keeping track of size and capacity is still pretty
thin. It's not like it's a linked list or something.

The overhead is thin but non-zero.

~~~
FartyMcFarter
That overhead can be thin or heavy, depending on the operation.

Doing "push_back" requires checking if "size < capacity", so this operation
has a lot of overhead even for std::vector instances that never reallocate
storage.

~~~
MauranKilom
Here it would be great to see if the optimizer (which was only on O2 for
unfathomable reasons) understands the reserve() beforehand to the point that
it can eliminate those checks. You'd have to look at assembly for that.

~~~
thestoicattack
I think Compiler Explorer shows that it usually doesn't, unfortunately.

------
jonstewart
The virtues of the STL are that your code is, by default, typesafe and Not
Slow. The article shows a few techniques for how to go from Not Slow to fast,
mostly by fiddling with the data structures, and these jibe with my
experience. In a nontrivial program, you will have your hot code and by
creating custom data structures that make different trade offs than the STL
(typically eschewing features like initialization, resize, etc), you can get
some gain. But that effort isn’t worth it for the rest of your program, and
yet the rest of your program is Not Slow.

The algorithm discussed also involves matrix math. It’s not object oriented,
it’s not data processing. So, there’s just naturally not that much difference
between C and C++ in this domain.

------
pjungwir
> I made a meshopt_Allocator class that could allocate large blocks of typed
> data and remember the allocated pointer; at the end of the scope all
> allocated blocks would be deleted.

I only write occasional C, and no C++ since college, but I think this Arena
pattern is drastically underused. I'd love to see it in web frameworks, where
every allocation inside a request comes from the same place, and at the end
you just give it all back. It seems like you could even offer that in Ruby.
Does Rocket use anything like this? It seems like the kind of thing Rust folks
would take advantage of.

Postgres memory allocation follows an Arena pattern, where you use palloc to
grab memory, but you rarely have to free it, because it is all freed when the
"context" completes. There are nested contexts for things like the connection,
the transaction, the sql statement, a function call, etc., so as long as
you're allocating from the right context, you can practically ignore cleaning
up after yourself. (This is from the perspective of a frequent extension
author but someone who has only barely contributed to the core project, so
perhaps a more expert contributor can correct me and/or elaborate.)

EDIT: Btw, I really enjoyed the article; thank you for sharing your
experiences with us!

~~~
barrkel
A nicely tuned generational GC should end up with first and second generations
effectively as arena allocators that get recycled very cheaply. When the time
comes around to collect the second generation, it should have almost no live
data, as it will only be filled with whatever was in flight across all the
times the first generation was collected.

When I understood this, it was an aha! moment for GC languages in stateless
server contexts. I could see that for a properly written server - ideally
keeping any long-lived mutable memory like caches off-heap - GC overhead could
be negligible.

~~~
anarazel
I'm very doubtful that's really true for databases. A lot of memory freed this
way is _not_ short lived. E.g. the contexts for running [parts of] an
analytics query can both be large and quite long lived. And it's crucial that
the memory is available again the instant the last query [part] finished,
otherwise it's quite realistic to run out of memory. And adding latency by
running through the many GB of otherwise used memory in hypothetical older
generations isn't acceptable either.

~~~
barrkel
I wrote _stateless_ servers, if you missed that bit.

Anything requiring large semi-long-lived intermediate buffers would need a
different approach, I agree. Similar to caches; you don't want a mid-life
crisis in a generational GC.

------
MauranKilom
Main criticisms from my side (that have not been discussed to death already):

\- Why O2? Why not O3? You're tuning your code for maximum performance and
then leave the optimizer halfway? That'll of course disadvantage code with
more abstractions.

\- Compile times are improved by dropping STL headers - that's why precompiled
headers exist. Having that factored into the comparison would indeed be
interesting, sadly this was not done.

\- MSVC is slow in debug mode because it's doing every debug check it can. If
that's not what you want, you can just change the iterator debug level. I was
hoping the author would figure as much after finding the gcc/clang switches
(and _complaining that they were off by default_ \- very ironic) with note 6
but no dice.

\- Regarding the choice of title: Almost all performance improvements were of
algorithmic/data structure nature. That's completely natural for the level of
performance tuning here. And I wouldn't really care if those specialized
implementations are in C++ or C, do what you want. Just don't implement them
in C and then draw conclusions from comparing them against the C++ STL under
the flag of "Is C++ fast?". I think a better title for the article would've
been "Are defaults fast?".

------
mikece
Better question: Can C++ be fast? Yes. But depending on the skill -- or lack
thereof -- of the developer it can be dreadfully slow. Besides, speed isn't
the best metric for judging a language. In the late 90s there was a joke among
Windows desktop developers: Which is faster, C++ or VB6? The answer was "VB6,
by six months" and there was a ton of truth to that statement (and by the time
the C++ version would have been done the parts of the VB desktop app that had
performance issues could have been identified and the logic replaced with C++
COM Objects).

The language is just a tool; USE the tool, don't be a tool.

------
Laakeri
Not a big surprise that hand implemented data structures with domain specific
optimizations are faster than generic standard library implementations.

------
Const-me
Indeed, standard library is often slow. Sometimes by orders of magnitude.

Here’s an example where a fast linked list implementation (not mine,
`CAtlList` from ATL) approaches or outperforms std::vector:
[https://github.com/Const-me/CollectionMicrobench](https://github.com/Const-
me/CollectionMicrobench)

Fortunately, in C++ we don’t pay for features we don’t use. If you want fast
code, no need to go back to C, you only need better C++ containers.

------
CoolGuySteve
C++ is relatively fast but MSVC’s STL library’s debug performance is abysmal.
It’s been like this since at least MSVC 2008 too. I’m not sure why Microsoft
doesn’t think it’s a priority to improve.

~~~
puetzk
It's because it's trivial to improve. The reason the MSVC STL is so slow in
debug mode, is because it's _really_ debug; they pull out all the stops to
bounds-check every dereference, keep a generational count to detect iterators
that could potentially have been invalidated by an operation that moved
elements or reallocates the container (and do so whether or not the potential
resize actually happened), etc. This adds a ton of code to the iterator paths,
and (due to that code size) loses most inlining opportunities.

If you want it to be as fast as other implementations, ask it to do less of
this. They provide [_ITERATOR_DEBUG_LEVEL]([https://docs.microsoft.com/en-
us/cpp/standard-library/iterat...](https://docs.microsoft.com/en-
us/cpp/standard-library/iterator-debug-level?view=vs-2017)) for exactly that
purpose. I think their choice of default (Debug means you want it to catch as
many bugs as it can, and Release means it should be fast) is appropriate.

If they hadn't provided the knob to adjust this I'd agree they had a problem
for some use-cases, but if you want the faster-but-less-thorough mode you just
have to ask for it.

~~~
gpderetta
As you explained, the debugging mode for STL is well beyond normal debugging
mode (i.e. no optimiziations, all debug symbols). It explicitly changes
complexity guarantees of the stl to catch issues with iterator invalidation
and other nasty bugs. As such it adds a considerable runtime cost to any use
of the STL.

In a way it is comparable to the overhead of the sanitizers available in other
compilers.

IIRC MS chose to enable it by default in debug mode as part of their effort of
fortifying unsafe C and C++ code against security bugs, but of course it has a
large penalty.

libstdc++ has a similar debug mode, but it is disabled by default, as, in
addition to be more expensive, it also breaks the ABI.

------
Ragnarork
> Release performance also slightly increased across the board - this is
> because for many of our arrays, the default initialization performed by
> std::vector’s constructor is redundant as we’re going to fill the array
> anyway. With std::vector, you can either resize a large array and then
> compute the items (which requires default-initializing every item
> redundantly), or reserve and push_back repeatedly (which requires a bit more
> code for adding each item, and this overhead can also add up). With a custom
> container it’s easy to have an option to skip initialization - in fact, in
> our replacement that’s the only option since it’s easy to memset the array
> manually if necessary.

I have a hard time to get the rationale here. Is the author implying that
using memset is inherently better than initializing an std::vector with the
constructor that takes a count and a default value, or resetting it with the
same variant of .assign()? Skimming through the code that's linked in the
article, it looks like there's no use case where either the former or the
latter wouldn't fit.

~~~
kbsletten
I read it as the author almost never uses the uninitialized data and when they
do need a zeroed array it's simple to do so why pay the cost to initialize the
elements when you're about to set them anyway.

~~~
kllrnohj
But you can easily avoid that cost on std::vector, too. std::vector doesn't
default-initialize unless you ask it to via resize(). reserve() doesn't
initialize, though, it just allocates. Take this toy example:

    
    
        #include <vector>
        #include <cstdio>
    
        struct MyFoo {
            MyFoo() { printf("default ctor\n"); }
            MyFoo(int i) { printf("Initialized with %d\n", i); }
            MyFoo(const MyFoo& foo) {}
        };
    
        int main() {
            std::vector<MyFoo> myvec;
            myvec.reserve(100);
            printf("resize(2)\n");
            myvec.resize(2);
            printf("emplace_back()\n");
            myvec.emplace_back();
            printf("emplace_back(1)\n");
            myvec.emplace_back(1);
            printf("push_back(MyFoo{1})\n");
            myvec.push_back(MyFoo{2});
            return 0;
        }
    

It will print:

    
    
        resize(2)
        default ctor
        default ctor
        emplace_back()
        default ctor
        emplace_back(1)
        Initialized with 1
        push_back(MyFoo{1})
        Initialized with 2
    

Only the resize() call did a default initialization "silently", nothing else
did.

~~~
thestoicattack
The tradeoff is that emplace_back and push_back need to check the capacity
(even though they won't reallocate because of reserve). Whereas with resize,
assignments into the initialized area need no checks at all.

------
lordnacho
With great power comes great responsibility.

C++ is no different. If you want it to be blazing fast, you need to tell it
exactly what you want. What data structure do you want, where do you want it,
where should it ask for more memory if needed?

If you don't do that, there's some sane defaults but the compiler doesn't know
whether you are going to relocate the structure or how you plan to access it.

------
kllrnohj
I'm confused by the premise:

> dropping C++11 requirement allowed me to make sure anybody can compile the
> library on any platform, removing std::vector substantially improved
> performance of unoptimized builds

What platform doesn't have C++11 support? And why is the performance of an
unoptimized build interesting? -O2 is basically a standard compiler flag...?

------
jlarocco
Interesting, but not necessarily surprising. It's pretty well known that the
STL favors generality and interface consistency over speed.

In any C++ conference talk about performance the speaker's almost guaranteed
to mention that their project uses their own optimized library instead of the
STL.

------
heywire
The most interesting part of this article to me was introducing me to Jonathan
Blow and his Jai language. I've skimmed over some of his videos, and they look
quite interesting. The compile time execution of any code supported by the
language looks especially interesting.

------
bayesian_horse
C++ gets you into trouble really fast ;-)

------
bluescarni
What a terrible article.

It starts with the comparison of a general-purpose hash table with
specifically-tailored one.

Then it throws in a switch from a comparison-based sort to a radix-based one.

Then, the stunning discovery that std::vector value-initialises its elements
(fixable with 3 lines of a custom allocator, if you don't want that
behaviour).

In the middle, it preaches about portability while at the same time advocating
the use of __builtin functions vs standard functions, and type-punning floats
to int and back (undefined behaviour in C++).

And all of this for a 572ms -> 320ms performance improvement?

~~~
gpderetta
In the grand tradition of HN i haven't read the article (but in my defense it
is blocked by work's firewall). Still, if he claims that unordered_map has
issues he is not alone. It is well known that the standard requirements
preclude a more efficient implementation.

And the issue with vector value initializing it's elements is also well known
and programmers have been asking for a solution (more user friendly than a
custom allocator) for a long time.

~~~
jcelerier
I don't understand the problems. Want a better hash map ? Use whatever makes
your day here : [https://tessil.github.io/2016/08/29/benchmark-hopscotch-
map....](https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html) ;
they are all header-only just like the standard library's.

Want a vector that does not initialize its elements ? Ask and thou shalt
receive:
[https://github.com/aguinet/pector](https://github.com/aguinet/pector)

The __whole point __of C++ is to make it easy for people to write generic
libraries beyond de standard base provided by the stdlib. So why won 't you
use those ?

~~~
gpderetta
Oh, I'm in violent agreement. The single biggest contribution of the STL is
its set of concepts more than the actual implementations. If you do not like
the specific tradeoffs for a container or algo implementation, you can swap it
for a different implementation often without code changes. I.e. you do not
need to remove abstraction, you just swap it for a different one.

Still it is fair to critique the specific tradeoff done by the standard
library.

~~~
stochastic_monk
It’s the linear chaining effectively required by the standard. I had an
application years ago which was 10x as fast after dropping in khash over
unordered_map.

~~~
gpderetta
IIRC that's because of the iterator and address invalidation requirements that
effectively require an node based implementation. But if your code does not
rely on these guarantees then, as you suggest, you can swap it with a
different implementation with the same interface.

You do not have to pay for what you do not use.

------
wmu
There was an article on HN, where the author stated that they didn't like to
write own algorithms "like in '90".

In this context, the Arseny's article should be titled: "How to be old-school
and tailor algorithms & data structures to your needs". I have this haunting
feeling that people nowadays are afraid of "reinventing wheel" even though
it'd pay off. A recurring argument is that the standard library or boost or
something available on github is better than a custom solution. But as we see,
there are cases where saying "nope, I'll do better job myself" has sense.

------
kensai
"C with structs" never heard of this saying. What does it mean exactly?

~~~
jng
The first version of C++ ever, designed by Bjarne Stroustrup at AT&T as a thin
layer on top of C, was called "C with classes". It was implemented as some
kind of source code preprocessor that took ".cc" code and output actual ".c"
code, probably not even fully parsing the input code.

It is already a somewhat funny first joke saying that the subset of modern C++
that's a nice language is just the C part and the "class" paradigm ("C with
classes").

It is another second somewhat funny joke to say that actually the nice part is
only an even more restrictive subset, "C with structs". Yes, structs and
classes are virtually equivalent in C++, but let's assume they mean structs as
in "classes without member functions". Which were already present in C. Which
is why it is funny.

Jokes are never funny when explained :/ Source: I'm a somewhat experienced
stand-up comedy practicioner, apart from a very experienced software
developer.

I wholeheartedly recommend reading Stroustrup's "Design and evolution of C++",
gives you so much valuable and interesting background.

~~~
pjmlp
It is even funnier that all major C compilers, and in some cases libc, are
nowadays implemented in C++.

~~~
pmarin
No it is not (funnier).

~~~
pjmlp
From a former C++ advocate on USENET point of view, it surely is.

------
chrisbennet
_" removing algorithm includes sped up compilation."_

Why is he optimizing for compile times when his compile times are only 1/2
second the start out with? Interesting article though.

~~~
twtw
1/2 second for this single file, not for the whole project. The bit you quoted
about removing includes was about the changes throughout the project.

------
lbj
There are some valid points on optimization here, but its always incredibly
tricky to draw conclusions from a series of microbenchmarks.

------
londons_explore
I don't see why anyone considers compilation time.

Your code will be compiled only once for your customers, yet run millions of
times. Clearly runtime is millions of times more important than compilation
time.

If compilation is taking too long, start compiling in the cloud.

------
rusabd
The headline is a click bait. Slightly better one would be "is idiomatic C++
fast"

------
adgasf
There isn't anything you can make the processor do in C that you cannot also
make it do in C++ (if I am not mistaken!) Given that, C will only appear
faster if you are not using C++ to its full potential. This might be because
you don't know what you're doing or because the C++ language makes it
unreasonably awkward. Most articles I have read like this are the former,
unfortunately.

~~~
faissaloo
No, C will be faster because you have more control, in the same way that
Assembly will always be faster than C.

~~~
gmueckl
C++ allows you to write code that is equally expressive as C. It is no longer
true that every valid pice of C is also valid C+++, but the deviations are
purely minor syntactical differences. I know no C construct for which a C++
counterpart does not exist. Please enlighten me if you have an example.

~~~
mikulas_florek
[https://en.cppreference.com/w/c/language/restrict](https://en.cppreference.com/w/c/language/restrict)

~~~
gmueckl
Replace it with __restrict and you're fine.

~~~
mikulas_florek
not standard c++

------
maccard
I wonder if his MSVC debug performance wors would have been solved by linking
against the release CRT

~~~
Const-me
I don’t think you can, it won’t build.

There’s a supported way to speed up debug builds by a huge factor, for the
price of less runtime checks.

[https://docs.microsoft.com/en-us/cpp/standard-
library/iterat...](https://docs.microsoft.com/en-us/cpp/standard-
library/iterator-debug-level?view=vs-2017)

~~~
maccard
Sure it does, I use it every day!

~~~
Const-me
You can't link debug builds with release CRT. Won't link. Here's an example of
missing symbols: __imp__invalid_parameter __imp__CrtDbgReport
__imp__CrtDbgReportW

You can workaround by undefining DEBUG, _DEBUG, defining NDEBUG, etc., to make
headers think it's a release build, but then it won't be a debug build
anymore.

~~~
ncmncm
If your goal is to be able to step it in the debugger and follow what is going
on, then it is definitely still a debug build.

If you want sanitization instead of stepping through the debugger, use that.

The people who are best at debugging avoid debuggers entirely, and use logging
statements inserted in release-built code, and little proofs. It is hard to
persuade people who don't think that way, but it is the only route to mastery.

~~~
Const-me
I'm very good at debugging and when I have choice I use all the tools I can
get. Not only I use debuggers, I extend them to do what I need for particular
project, e.g. autoexp.dat/natvis/custom plugins when coding C++ in VC.

At the same time I also use logging a lot. These two things aren't always
mutually exclusive.

Only sometimes they are. Some platforms don't have good debuggers. For other
stuff it's the opposite, e.g. you can't log from code running on GPU (very
hard to accomplish, borderline impossible) but there're specialized GPU
debuggers.

I don't think people who use just logging, or just debuggers, are the best.

------
tqy
They are bloating C++ so much that it'll end up as slow as Python or any other
high level language with none of the advantages of being a high level
language.

Just the fact that we're asking ourselves "is C++ fast" should be frightening,
for a language that has always rivalled C closely.

------
hathym
yes

