I agree with your depiction of C++. In fact, one of the benefits of C++ is that it is convenient to use stack allocation rather than heap allocation. This can really simplify memory management. The trick is that you have to choose a different idiom for your idiomatic C++ ;-). The trick is to always know who owns the memory and to never allocate memory in libraries. You use dependency injection, always pass by reference and always clean up in your destructors. If you are forced to allocate something in a library, you build a wrapper to deallocate it (or sometimes copy it when you receive the memory so that you can own it).
It takes some experience to build applications this way, but it is well worth building that experience. C++ is still my language of choice for anything that requires fine control of memory and attention to performance. Rust looks like a very possible successor, but I agree that the lack of incremental compiling makes it not useful for large projects at the moment.
> I agree that the lack of incremental compiling makes it not useful for large projects at the moment.
Whoa there. Let's not exaggerate the scope of the problem. Large projects in Rust usually consist of many crates (in Servo, 150+). Rust absolutely has incremental compilation on the level of the crate, so the compilation times are similar to what you see in C++ with per-directory unity builds. This is the same story as Go, for example, and people don't say Go isn't suitable for large projects; incremental compilation isn't even on Go's roadmap.
> one of the benefits of C++ is that it is convenient to use stack allocation rather than heap allocation.
Not quite. With its destructors (and the RAII that come with them), C++ makes it easy to follow a scoped discipline. Allocations are easily scoped, but they don't necessarily happen on the stack.
Strings and vectors for instance, are typically allocated on the heap, assuming you're using the default allocator (which most people do anyway). While this is convenient and make things simpler, that's quite the runtime overhead, and causes latency problems similar to those of a genuine garbage collector (malloc() and free() aren't exactly constant time).
> never allocate memory in libraries
Now that can reduce the number of allocations in a program. Note that this also rules out most of the STL: its containers call their (possibly user defined) allocator themselves.
It is quite possible that I'm out of date (haven't used C++ in anger for the better part of a decade), but local variable allocations have always historically been on the stack. Just don't use new. Arrays will be allocated on the stack as long as they are fixed length.
> local variable allocations have always historically been on the stack
And they still are, thank goodness. My point was that as soon as you call a constructor, all bets are off: for instance, merely declaring an std::string allocates on the heap, local variable or no. But it seems you already knew that.
I think it is important to distinguish scoped discipline from stack allocation. The former is a way to program. The later is an implementation detail (modulo performance). Your wording was a tiny bit sloppy, so I jumped at it.
It takes some experience to build applications this way, but it is well worth building that experience. C++ is still my language of choice for anything that requires fine control of memory and attention to performance. Rust looks like a very possible successor, but I agree that the lack of incremental compiling makes it not useful for large projects at the moment.