> You'll find crap in C++ like const *const char &, and hell if anyone knows what that really means since even though the pointer to a const to a const reference is consted to hell and back, oh look you can still increment it. They'd have been better off to just invent a new keyword: doesnotfuckingchange and stop there.
As I recall, Stoustrup originally wanted to call the const keyword 'readonly', which is a more accurate description of what it does (const data is not constant, it's read-only: something else can change it while you're not looking, but you can't change it). They didn't, for compatibility reasons with C.
That said, the const keyword allows you to move contracts about, e.g., "this method does not alter its object", from the programmer's head into the code where it can be checked by the compiler. (unless you have people doing stupid things with mutable or const_cast).
But yeah, C++ has flaws. Big flaws [1]. Anyone who tells you otherwise is probably uninformed or lying. The interesting question is, why do people keep using it in spite of its flaws? Certainly a large part of that is inertia, but I don't think that that's the only thing. I think there's a niche where there's really not a lot of good options other than C++, and that's quite unfortunate. But "C++ sucks" removes the possibility that there's anything useful there, making discussion of better alternatives (e.g., would D work? what is it about C++ that makes it useful? how do these languages compare? etc.) impossible. See, for example, Rob Pike's complaint about why C++ programmers aren't all moving to Go, which essentially ignores a bunch of reasons why you might use C++ (since Go is not a replacement for them). See [2], [3].
Stroustrup dixit: "Within C++, there is a much smaller and cleaner language struggling to get out."
Rust?
> The interesting question is, why do people keep using it in spite of its flaws? Certainly a large part of that is inertia, but I don't think that that's the only thing.
Ownership management. Which has been expanded into full lifetime management (including that of borrowed pointers) in... Rust!
Static polymorphism. Which is implemented in a crappy way in C++, but at least is doable:
1. Non-specialized templates: Type constructors.
2. Concepts (sadly only in the heads of programmers): Type classes.
3. Exported typedefs and type traits: Type families.
> See, for example, Rob Pike's complaint about why C++ programmers aren't all moving to Go, which essentially ignores a bunch of reasons why you might use C++ (since Go is not a replacement for them).
Yeah, Rust is really interesting, and something I'd like to try on a real project. Hopefully I'll be able to do something with it this spring. But it's certainly more appealing as a replacement than, say, Go, which I don't think is really even that interesting as a language (but this is a personal opinion which I'm not willing to argue about on the internet).
Rust also would immediately solve some things I find particulary annoying about C++ (lack of sum types, inability to create new types that behave identically to old types, etc).
One thing that I think would be nice to have in a hypothetical language is vector support for integral types, the same way OpenCL has.
The Eigen library for C++ is IMO a really good example of the "Edward C++hands" phenomenon. It's a terrific library, using C++ template magic to produce optimized assembly for your platform, to achieve performance you just can't get with C. On the other hand, it can be annoying to use, since there are places where the C++ warts come out, and the developers have to put in an extraordinary amount of effort just to get there. If you had this kind of thing built into the language, it's much easier for everyone involved: compiler authors, programmers, library developers, etc.
People keep using C++ because there aren't any real competitors in its niche. It offers the same performance level as C, while having substantial improvements: namespaces, templates, RAII, operator overloading, type-safe containers.
These are things that can help raise the abstraction level, while not giving up performance.
There are many "real competitors" to C++. The biggest one is C. Many things were written in C in recent years: the Postgres database, networkmanager, pulseaudio, the Linux, BSD, and Mach kernels, zeroMQ, sshd, Xfce, Gnome 2 and 3, the list goes on and on. You may not like it, but people chose to write these things in C when C++ was available. Similarly, Apple chose to base most of MacOS on another non-memory-safe, (usually) non-garbage collected systems programming language: Objective-C. We can debate the merits of these choices, but to deny that they exist is just prima facie incorrect.
Sure, there are many competitors to C++ and that's not something that I'm contending. What I said was that there aren't any real competitors in its niche. If you want more powerful abstraction features, while preserving C-level performance, there aren't many real options. If you don't want or need those things, then C is a perfectly good choice.
There are many other languages that raise the abstraction level, but most do it at a performance cost. As for Objective-C, I'm fully convinced that it would be an obscure niche language today if it hadn't been for Apple basing OS X on NeXTSTEP. I don't see it as a competitor to C++ unless you're actually working in the Apple ecosystem.
C++ has one big flaw the way I see it, and that is, it is incredibly difficult to learn well and it's very easy to teach badly.
I have been programming C++ for many years now, I still look back on code I wrote a couple of years ago and can see how my style has development, and I won't even dare review the code I wrote whilst learning the language.
That said, once you've straddled to learning curve, I really do believe that it is a great language for more than just niece core of use cases. Having learnt it there would be very few cases I would use C over C++, nor would I use an other compile "General purpose" programming language, like Java , D, Go or C#. The "next level up" for me is scipting with python or bash and the step down is asm or inline intrinsics. I am happy with C++ in the middle of that wide chasm.
>" You have to do all the same memory checks, use valgrind, make sure you've got destructors, and then that's made more complex by templates, object lifecycles, exception rules, etc.. Frankly C++ doesn't have better memory
management than C, it just has more complex management."
I strongly disagree with the author, and I suspect he is biased for the "old school" C++ (as he called it). For instance:
>make sure you've got destructors.
Objects allocated on the stack are guaranteed to be destroyed and hence their destructors to be called. Which is very convenient if those objects are owners of a resource (like a DB connection).
>"and then that's made more complex by templates, object lifecycles, exception rules, etc.."
Object lifecycle are well defined but if all is an OOP problem not a C++ one.
As for the rest, the beauty of C++ is that if there is something that doesn't apply to your project, then you don't use it. Your are not required to use exceptions or templates if you don't want to.
> "Frankly C++ doesn't have better memory management than C, it just has more complex management"
Again, if you want to it can be complex, or it can be the same management you would do in C. That's a flexibility that simply you don't have in C.
Agreed. His Boost complaints are odd, too; even in 2010 it certainly didn't take "forever" to build Boost and its templates are for the most part very logical and essentially hidden to you (see for example boost::format, which does pretty much exactly what he says he wants out of a formatter).
He's got a point that for mongrel2 the full feature set of C++ doesn't necessarily make sense, but having it available when I want it is really valuable to me. For my game, I literally couldn't do what I'm doing without some really big, really gross crap that would be multiple times the code I have. (Faking polymorphism with state machines makes everyone sad.)
> Your are not required to use exceptions or templates if you don't want to.
This is absolutely true -- at least if you're working alone. But I've always found the whole "let's use a subset of c++" to be untenable on long projects. Somebody always joins that's infatuated with Alexandrescu, or some random error handling strategy, and then you end up in endless debates about concepts vs. abstract base classes. Those debates can be fun, but they seem to too often leave behind hurt feelings and demoralized team members.
If you just throw back to c, all you have to deal with is the argument that "we should really use c++, because <insert some random thing>". Those don't last too long, you just have to respond that it's a c project :)
> endless debates about concepts vs. abstract base classes
Really? Generic programming's better static error detection facilities makes it the superior alternative with respect to object-orientation, whenever you can choose between the two. This pretty much settles the question IMO.
The whole time I was reading this I couldn't help think of all the "ported x to 30 lines of javascript" headlines. By that I mean, just because it can be done in a language, doesn't mean it's the best fit.
I think his best point was about dropping in boost. It doesn't make sense to add more code, increase compile times, and complicated stack traces just to use C++. I have to admit, I go out of my way to use newer tech sometimes even though I know it'll slow me down. But, we (I) need to remember something about Software Engineering -- at the bottom line, we're building software. Its language and design should reflect the best possible result, and while that doesn't always mean speed, it does mean using the best tools to solve that problem.
When using modern compilers, the overhead for Boost is pretty minor. I get that this was a big deal some time ago (I wasn't using C++ then, so I can't say myself) but using Boost with clang and precompiled headers don't cause a significant increase in compile times except in the case of a clean, which is rare enough for me that I just use that as a chance to get up, move around, etc.
Boost can weird your stack traces a little, but they exhibit in predictable ways that you can usually quickly reason out if you understand what your stuff is doing.
Imagine C is like giving a wannabe tinkerer a knife; then C++ would be like giving him a knife, blowtorch, dremel.
With the C guy, you more or less know what kind of damage he can do, and what kinds of trouble he can get into. So you are able to look out for that.
The C++ guy, OTOH has exponentially more ways to cause damage.
Basically, both are tools, which, in the hands of a skilled artist, can do wonders. But in the hands of the inexperienced (99%), C++ is a lot more dangerous and complicated.
Not really. C++, at least modern C++, is a huge improvement in terms of safety over C. The problem with C++ is that this improvement has been achieved in a clumsy way: instead of providing clearly differentiated means of static abstraction (e.g., non-specializable generics for parametric polymorphism and concepts for ad-hoc polymorphism), we get templates, which have been equipped with all sorts of corner cases (specialization, SFINAE).
Note that had mongrel2 been written in c++, I would not be working on it right now. Not because I necessarily think it's bad, but because I don't know hours to write good c++. there are all sorts of tricks to making c++ tractable[1] and I just don't have enough familiarity with them.
To me, I don't care this kinda debate. I just keep improving my C and C++ skills. Whatever language my manager wants to use. I just use it. (I can write Python, Haskell and Java, C# too)
Right. I don't see why we're having this discussion. You use C++ if you want to deal with higher-level objects. The argument of, "memory management is easier," is a total fallacy, just like has been pointed out in that list message.
There is absolutely no reason not to use C++ in modern software development.
C++ gives you deterministic object lifetimes without the overhead of manual management through the RAII pattern and smart pointers. It gives you std::string, which is as easy to use, if not easier, than char*. It gives you parameterized types and real value semantics for user-defined types. There are even template versions of strcpy and friends which pass implicit length parameters to strcpy_s and friends, which prevent a whole class of buffer overflow bugs which have been the bane of C programmers since the language came into existence.
With all the added safety and convenience that C++ gives you over C, it is literally insane to use C where C++ could be used.
There is absolutely no reason not to use C++ in modern software development.
Its nightmarishly complicated and gives you 1000 ways to blow your foot off, and maybe one or two to get the job done properly. After about 18 years of C++ development I still go for C sometimes. C is a lovely language that is much easier to learn. I cannot believe anyone would cheerlead for C++. Its a necessary evil.
There's plenty of reasons to prefer C over C++, but I don't feel like this post is doing a good job of capturing them. I was much more amused by Linus's version: http://lwn.net/Articles/249460/
IMO the most confused part of this post is to dismiss templates as "stupid". I myself am rather "C-leaning" but I can acknowledge that some C++ features are well thought out. Templates enable a lot of the "good C++" in a number of ways.
My favorite example: for things like callbacks and lambdas. In C you often find yourself using function pointers for this. With templates, you can make that a compile-time cost instead of a runtime cost. So your callback can get inlined right inside the caller. One practical result of this: things like std::sort are faster than libc's qsort.
Similarly, he is right to say that exceptions can introduce memory leaks in C++... But the C++ advocate's position would be that the RAII pattern avoids this. And when you get into that habit, so long as you are consistent with it, I can't say the whole thing is too bad. It's rather elegant.
Personally I think the problem is not C++ itself, rather that it asks a lot of developers to be able to navigate towards the "good C++" and avoid the costly anti-patterns. To make matters worse, people don't agree about what the "good C++" is. IMO this is all more of a social problem than a technical one. Which leads me into something similar to Linus's argument, to choose C to "keep the C++ programmers out" -- not that it's impossible to do C++ well, but that there's a large community of people who are "doing it wrong", even if you can agree what "right" is.
I and my colleague ported a mature project (the fish shell) from C to C++, over a period of about a year, so our experiences are relevant. Like many projects, fish uses C++ as mainly a better C, without embracing exotic templates, exceptions, smart pointers, boost, or other high-powered features. Most of Zed’s points do not apply to this style of programming, and anyone considering a port to C++ ought to consider it.
C++ as a better C does impose some costs, such as longer compile times, more cryptic error messages, nastier backtraces, and losing compatibility with some older systems. But these are tolerable, and on balance the benefits are worth it. In one case, fish strayed and used shared_ptr, which caused compatibility pain. This suggests we’ve hit a sweet spot, where if we adopted more C++ features we’d start to see a greatly increased cost.
Just using std::string would reduce the mm noise and make the code easier to read and reduce the chances of memory leaks.
This is indeed what we found. The memory management simplification was a huge deal, and that drove my decision for the port. However, the big win came not from the specifics of C++'s memory management, but from its regularization: imposing a single memory management scheme.
Like most C projects, the shell was rife with char . When you see a char , you can't immediately know who owns the string, who is responsible for deallocating it, and how it should be deallocated. std::string lets you reason locally about the code, but so too do C libraries such as GObject, CFString, etc. C++ won out over these alternatives because it's more widely supported and has a deep pool of potential contributors. But the C++ "feature" that mattered most was not that its memory management scheme was better, but that it existed.
C is really the best because it is the lowest friction access to all the POSIX stuff you need
This is a big concern that disqualifies most other languages. For example, Go or Haskell cannot easily do checks like `#ifdef VDSUSP`, and have no guaranteed semantics for threads after fork. C is undisputed king here! But C++ doesn’t impose much additional friction as long as you stick to the POSIX primitives. e.g. pthread_* instead of std::thread or std::lock. There is no “huge bother.”
The semantics of destructors are incredibly confusing, especially with exceptions.
Destructors are indeed terrifying when in the direct gaze of a fully operational C++ battlestation. However they are simpler in a suitably sane subset of C++. The fish shell, for its part, disallows all exceptions, even compiling with -fno-exceptions for a binary size savings.
No matter what, unless the language has a GC built-in, then C will have simpler and more predictable memory usage.
As I argued above, the important aspect here is not the choice of language, but the choice of memory management scheme. It is possible to make memory management simple and predictable, or instead ad-hoc and haphazard, in both C and C++. The key difference is that C++ comes with a scheme built-in (which you may or may not choose to use), while C does not. I don’t know how mongrel manages memory, but the “no matter what” claim is obviously wrong.
I couldn't imagine trying to use the string output stream stuff to craft messages and things.
Indeed: wstringstream is a big memory hog! But choosing C++ does not commit you to using the stream formatting syntax, nor does it preclude using printf-style formatting. fish uses printf-style formatting everywhere.
On the flip side, the simple task of appending two strings is awkward in C. Either you have a fixed size buffer, or you commit to some string object type, which then requires manual copying and cleanup. C++’s strings have flaws, but they definitely simplify string handling compared to C.
Even something as simple as casting a float to an int is a pain in the ass involving some weird template like syntax that frankly makes no sense.
>"Leaving it off here, but I hope I showed how Zed’s points apply to using C++ in all its glory"
All you said make sense but some points are still arguably. The thing is that C++ feature set is big enough so any combination of them would probably be a good fix for a given project.
For instance, you showed some advantages of using “C++ as a better C”, but I had seen horrible bugs originated by a careless use of a void* that could be prevented by using templates. So I would say that the experience change depending of the project requirements.
Also, about the C++ cast style thing, it is verbose indeed but it is almost like that on purpose, Stroustrup really wanted to discourage casting and in a lot of cases I am agreed with him, most casts can be avoided.
I'm a mongrel2 developer, and we don't use bare char pointers for strings either, in favor of the bstring library. Zed was off the opinion that it is superior to the c++ std:: string.
In contrast, Rust recently migrated the non-Rust parts of its native runtime from C++ to straight C. I believe the motivation as simplicity and to avoid any surprises with external linkage with non-Rust libraries.
You call C++ typecasts onerous, but does that mean you don't use them? I use them (because more C++ thumbscrews must be better), but, in my career, I think they have found only 2-3 compile-time bugs that would have been hidden by C typecasts. I think the C++ function-call-style typecasts (e.g. `size_t x = size_t(-1)`) are pretty elegant.
30 comments
[ 3.0 ms ] story [ 69.8 ms ] threadAs I recall, Stoustrup originally wanted to call the const keyword 'readonly', which is a more accurate description of what it does (const data is not constant, it's read-only: something else can change it while you're not looking, but you can't change it). They didn't, for compatibility reasons with C.
That said, the const keyword allows you to move contracts about, e.g., "this method does not alter its object", from the programmer's head into the code where it can be checked by the compiler. (unless you have people doing stupid things with mutable or const_cast).
But yeah, C++ has flaws. Big flaws [1]. Anyone who tells you otherwise is probably uninformed or lying. The interesting question is, why do people keep using it in spite of its flaws? Certainly a large part of that is inertia, but I don't think that that's the only thing. I think there's a niche where there's really not a lot of good options other than C++, and that's quite unfortunate. But "C++ sucks" removes the possibility that there's anything useful there, making discussion of better alternatives (e.g., would D work? what is it about C++ that makes it useful? how do these languages compare? etc.) impossible. See, for example, Rob Pike's complaint about why C++ programmers aren't all moving to Go, which essentially ignores a bunch of reasons why you might use C++ (since Go is not a replacement for them). See [2], [3].
[1]: http://bartoszmilewski.com/2013/09/19/edward-chands/
"I’ve been looking for a good analogy of what programming in C++ feels like and I remembered this 1990 Tim Burton movie, Edward Scissorhands."
[2]: http://blog.grok.se/2013/10/on-comparing-languages-c-and-go/
[3]: http://commandcenter.blogspot.se/2012/06/less-is-exponential...
Stroustrup dixit: "Within C++, there is a much smaller and cleaner language struggling to get out."
Rust?
> The interesting question is, why do people keep using it in spite of its flaws? Certainly a large part of that is inertia, but I don't think that that's the only thing.
Ownership management. Which has been expanded into full lifetime management (including that of borrowed pointers) in... Rust!
Static polymorphism. Which is implemented in a crappy way in C++, but at least is doable:
1. Non-specialized templates: Type constructors.
2. Concepts (sadly only in the heads of programmers): Type classes.
3. Exported typedefs and type traits: Type families.
> See, for example, Rob Pike's complaint about why C++ programmers aren't all moving to Go, which essentially ignores a bunch of reasons why you might use C++ (since Go is not a replacement for them).
Dude must be completely deluded.
Rust also would immediately solve some things I find particulary annoying about C++ (lack of sum types, inability to create new types that behave identically to old types, etc).
One thing that I think would be nice to have in a hypothetical language is vector support for integral types, the same way OpenCL has.
The Eigen library for C++ is IMO a really good example of the "Edward C++hands" phenomenon. It's a terrific library, using C++ template magic to produce optimized assembly for your platform, to achieve performance you just can't get with C. On the other hand, it can be annoying to use, since there are places where the C++ warts come out, and the developers have to put in an extraordinary amount of effort just to get there. If you had this kind of thing built into the language, it's much easier for everyone involved: compiler authors, programmers, library developers, etc.
These are things that can help raise the abstraction level, while not giving up performance.
There are many other languages that raise the abstraction level, but most do it at a performance cost. As for Objective-C, I'm fully convinced that it would be an obscure niche language today if it hadn't been for Apple basing OS X on NeXTSTEP. I don't see it as a competitor to C++ unless you're actually working in the Apple ecosystem.
C++ has one big flaw the way I see it, and that is, it is incredibly difficult to learn well and it's very easy to teach badly.
I have been programming C++ for many years now, I still look back on code I wrote a couple of years ago and can see how my style has development, and I won't even dare review the code I wrote whilst learning the language.
That said, once you've straddled to learning curve, I really do believe that it is a great language for more than just niece core of use cases. Having learnt it there would be very few cases I would use C over C++, nor would I use an other compile "General purpose" programming language, like Java , D, Go or C#. The "next level up" for me is scipting with python or bash and the step down is asm or inline intrinsics. I am happy with C++ in the middle of that wide chasm.
I strongly disagree with the author, and I suspect he is biased for the "old school" C++ (as he called it). For instance:
>make sure you've got destructors.
Objects allocated on the stack are guaranteed to be destroyed and hence their destructors to be called. Which is very convenient if those objects are owners of a resource (like a DB connection).
>"and then that's made more complex by templates, object lifecycles, exception rules, etc.."
Object lifecycle are well defined but if all is an OOP problem not a C++ one.
As for the rest, the beauty of C++ is that if there is something that doesn't apply to your project, then you don't use it. Your are not required to use exceptions or templates if you don't want to.
> "Frankly C++ doesn't have better memory management than C, it just has more complex management"
Again, if you want to it can be complex, or it can be the same management you would do in C. That's a flexibility that simply you don't have in C.
He's got a point that for mongrel2 the full feature set of C++ doesn't necessarily make sense, but having it available when I want it is really valuable to me. For my game, I literally couldn't do what I'm doing without some really big, really gross crap that would be multiple times the code I have. (Faking polymorphism with state machines makes everyone sad.)
Exactly my point. In C++ you have all those tools available and you won't pay for them until you start using them.
This is absolutely true -- at least if you're working alone. But I've always found the whole "let's use a subset of c++" to be untenable on long projects. Somebody always joins that's infatuated with Alexandrescu, or some random error handling strategy, and then you end up in endless debates about concepts vs. abstract base classes. Those debates can be fun, but they seem to too often leave behind hurt feelings and demoralized team members.
If you just throw back to c, all you have to deal with is the argument that "we should really use c++, because <insert some random thing>". Those don't last too long, you just have to respond that it's a c project :)
Really? Generic programming's better static error detection facilities makes it the superior alternative with respect to object-orientation, whenever you can choose between the two. This pretty much settles the question IMO.
I think his best point was about dropping in boost. It doesn't make sense to add more code, increase compile times, and complicated stack traces just to use C++. I have to admit, I go out of my way to use newer tech sometimes even though I know it'll slow me down. But, we (I) need to remember something about Software Engineering -- at the bottom line, we're building software. Its language and design should reflect the best possible result, and while that doesn't always mean speed, it does mean using the best tools to solve that problem.
Boost can weird your stack traces a little, but they exhibit in predictable ways that you can usually quickly reason out if you understand what your stuff is doing.
With the C guy, you more or less know what kind of damage he can do, and what kinds of trouble he can get into. So you are able to look out for that.
The C++ guy, OTOH has exponentially more ways to cause damage.
Basically, both are tools, which, in the hands of a skilled artist, can do wonders. But in the hands of the inexperienced (99%), C++ is a lot more dangerous and complicated.
1. See for example RAII rule of three, etc.
My personal favorite one is C though.
C++ gives you deterministic object lifetimes without the overhead of manual management through the RAII pattern and smart pointers. It gives you std::string, which is as easy to use, if not easier, than char*. It gives you parameterized types and real value semantics for user-defined types. There are even template versions of strcpy and friends which pass implicit length parameters to strcpy_s and friends, which prevent a whole class of buffer overflow bugs which have been the bane of C programmers since the language came into existence.
With all the added safety and convenience that C++ gives you over C, it is literally insane to use C where C++ could be used.
Its nightmarishly complicated and gives you 1000 ways to blow your foot off, and maybe one or two to get the job done properly. After about 18 years of C++ development I still go for C sometimes. C is a lovely language that is much easier to learn. I cannot believe anyone would cheerlead for C++. Its a necessary evil.
IMO the most confused part of this post is to dismiss templates as "stupid". I myself am rather "C-leaning" but I can acknowledge that some C++ features are well thought out. Templates enable a lot of the "good C++" in a number of ways.
My favorite example: for things like callbacks and lambdas. In C you often find yourself using function pointers for this. With templates, you can make that a compile-time cost instead of a runtime cost. So your callback can get inlined right inside the caller. One practical result of this: things like std::sort are faster than libc's qsort.
Similarly, he is right to say that exceptions can introduce memory leaks in C++... But the C++ advocate's position would be that the RAII pattern avoids this. And when you get into that habit, so long as you are consistent with it, I can't say the whole thing is too bad. It's rather elegant.
Personally I think the problem is not C++ itself, rather that it asks a lot of developers to be able to navigate towards the "good C++" and avoid the costly anti-patterns. To make matters worse, people don't agree about what the "good C++" is. IMO this is all more of a social problem than a technical one. Which leads me into something similar to Linus's argument, to choose C to "keep the C++ programmers out" -- not that it's impossible to do C++ well, but that there's a large community of people who are "doing it wrong", even if you can agree what "right" is.
C++ as a better C does impose some costs, such as longer compile times, more cryptic error messages, nastier backtraces, and losing compatibility with some older systems. But these are tolerable, and on balance the benefits are worth it. In one case, fish strayed and used shared_ptr, which caused compatibility pain. This suggests we’ve hit a sweet spot, where if we adopted more C++ features we’d start to see a greatly increased cost.
Just using std::string would reduce the mm noise and make the code easier to read and reduce the chances of memory leaks.
This is indeed what we found. The memory management simplification was a huge deal, and that drove my decision for the port. However, the big win came not from the specifics of C++'s memory management, but from its regularization: imposing a single memory management scheme.
Like most C projects, the shell was rife with char . When you see a char , you can't immediately know who owns the string, who is responsible for deallocating it, and how it should be deallocated. std::string lets you reason locally about the code, but so too do C libraries such as GObject, CFString, etc. C++ won out over these alternatives because it's more widely supported and has a deep pool of potential contributors. But the C++ "feature" that mattered most was not that its memory management scheme was better, but that it existed.
C is really the best because it is the lowest friction access to all the POSIX stuff you need
This is a big concern that disqualifies most other languages. For example, Go or Haskell cannot easily do checks like `#ifdef VDSUSP`, and have no guaranteed semantics for threads after fork. C is undisputed king here! But C++ doesn’t impose much additional friction as long as you stick to the POSIX primitives. e.g. pthread_* instead of std::thread or std::lock. There is no “huge bother.”
The semantics of destructors are incredibly confusing, especially with exceptions.
Destructors are indeed terrifying when in the direct gaze of a fully operational C++ battlestation. However they are simpler in a suitably sane subset of C++. The fish shell, for its part, disallows all exceptions, even compiling with -fno-exceptions for a binary size savings.
No matter what, unless the language has a GC built-in, then C will have simpler and more predictable memory usage.
As I argued above, the important aspect here is not the choice of language, but the choice of memory management scheme. It is possible to make memory management simple and predictable, or instead ad-hoc and haphazard, in both C and C++. The key difference is that C++ comes with a scheme built-in (which you may or may not choose to use), while C does not. I don’t know how mongrel manages memory, but the “no matter what” claim is obviously wrong.
I couldn't imagine trying to use the string output stream stuff to craft messages and things.
Indeed: wstringstream is a big memory hog! But choosing C++ does not commit you to using the stream formatting syntax, nor does it preclude using printf-style formatting. fish uses printf-style formatting everywhere.
On the flip side, the simple task of appending two strings is awkward in C. Either you have a fixed size buffer, or you commit to some string object type, which then requires manual copying and cleanup. C++’s strings have flaws, but they definitely simplify string handling compared to C.
Even something as simple as casting a float to an int is a pain in the ass involving some weird template like syntax that frankly makes no sense.
C++ typ...
All you said make sense but some points are still arguably. The thing is that C++ feature set is big enough so any combination of them would probably be a good fix for a given project.
For instance, you showed some advantages of using “C++ as a better C”, but I had seen horrible bugs originated by a careless use of a void* that could be prevented by using templates. So I would say that the experience change depending of the project requirements.
Also, about the C++ cast style thing, it is verbose indeed but it is almost like that on purpose, Stroustrup really wanted to discourage casting and in a lot of cases I am agreed with him, most casts can be avoided.
https://github.com/mozilla/rust/commit/508b7b9