That is fair to a point. Some GC languages (like Java) are significantly more inefficient than they need to be regardless of the GC.
Nonetheless, for performance C++ code you don’t see much malloc anywhere, directly or indirectly, so the efficiency doesn’t matter that much. That’s pretty idiomatic. I think this is the real point. As a C++ programmer, if you are not serious about eliminating dynamic allocation then you aren’t serious about performance. Since C++ is used for performance, you don’t see much dynamic allocation that a GC could theoretically help with. Most objects in the hot path have explicitly and carefully managed lifetimes for performance.
I use GC languages for quite a few things, but it is always for things where performance doesn’t matter. When performance matters, I’ve always been able to beat a GC for performance, and I’ve done my fair share of performance engineering in GC languages.
If you compile that code with Fil-C++, then you won't see much (or any) GC overhead. The GC kicks in for three things:
- malloc (this is the main client of the GC)
- stack allocations that aren't escape analyzed (these are rare, typically small, and generate minuscule GC load - it's common for code I've tested to have zero of these)
- Fil-C runtime internal allocations (these are super rare - for example if you call sigaction, pthread_create, setjmp, or dlopen then there's some GC object allocated behind the scenes - but you aren't going to be calling those a lot, and if you are then you've got bigger problems than GC).
I understand your perspective about GC languages. Most GC languages also come with other baggage, which makes it very difficult to avoid the GC. Most C++ code that avoids malloc ends up doing a bunch of `new`s when converted to Java. But C++ code that avoids malloc will avoid the GC if compiled with Fil-C++.
Fil-C’s compiler is GC aware.
Something to consider is that Fil-C permits you to do all of the things you would normally do, as a C programmer, to reduce or eliminate allocation - like having structs embedded in structs and avoidance of allocation in core algorithms.
This makes it quite different from Java or JS where the language forces you to allocate to basically do anything. I think folks conflate “GC overhead” with the overhead of languages that happen to use GC.