Comments like this perplex me. I am a full time C++ dev and I could just rewrite your comment woving the "++" to the other "C".
Really like that I can create a class that stores all the knowledge of one concept internally and if I wrote that correctly I never need to look inside it again. Even better, if I document the contracts of using a class I can carefully optimize it and have broad performance effects with small code changes.
Things like std::string are just so much easier to work with that their C counterpart and things like std::filesystem::path simplify (or use the boost one if you don't have C++17 yet) so many things and doesn't even have a C counterpart. I point these out as simple examples but in all the code bases I have worked on there are similar examples, like most games a class to represent 2d and 3d points, which are used to define AxisAlignedBoundingBoxes, which are needed for collision detection algorithms which them selves need several classes to describe.
Then I can build systems of a size and complexity I literally could not comprehend without those abstractions. And then the compiler enforces them for me so other people can use them safely as well. Why is it so much harder to do this in C if C is so much "simpler".
C++ has the issue that there are a lot of ways to hide magic, and a lot of hidden magic can blow up in unexpected ways if it interacts badly with other parts of the language that you do not understand.
The result is that you really need to stick to a subset of the language that has been chosen to work well together. Safely adding to that chosen subset is challenging. And it just takes one developer to create a major headache.
Every language can hide stuff. Classes, templates and operator overloads are just pretty wrappers for functions with better designed conventions for the common cases. Anyone can write "hidden magic" in any language with anything like these abstractions.
It is particularly easy to make this hidden magic in C. For example, there is no way to express who has ownership of a pointer or when a function expects a pointer or an array. I have seen plenty of C libraries that document things like this, but for each that does there are 3 that don't. For each one does document things like that, they do it differently with different conventions but for the same reasons, but I cannot even use common idioms to be safe I must understand every part of each library I call. It is much more clear what is going own in C++ when a function accepts or returns a std::unique_ptr and I cannot screw it up without trying hard.
What seems more important to me is exposing the relevant parts of the software when needed. If I care about the business logic (Even if its nots a business app... HP and Mana can be considered the business logic of a game) it can be hard to tease that out when lots of "hidden magic" is shoved in my face. But when I need to handle a new file format that the business logic requires indirectly I don't want to mess with the business logic. Having more tools to cleanly express this helps. So have a type that handles this IO while some other type handles business logic is indeed changing magic into "hidden magic", but it is also enforcing separation of responsibilities. Something much harder to do when your only real tool of abstraction if functions.
The only people I have met in real life that stick to anything like the "hidden magic" argument are the same people who advocate for single large functions. These people like their function on the order of hundreds or thousands of lines so they can "see everything". You aren't doing that are you?
The problem is not so much hiding stuff. It is being surprised by the interactions between features. The "can't get there from here" like trying to printf to an iostream. If you're not careful, simply scanning through a large file is several times slower than other languages. Template magic makes seemingly reasonable type names blow up into insanely hard ones to figure out. There are non-obvious patterns that you have to know such as RAII.
And good luck if you want to make things portable! I remember at Google being asked how I checked in unit tests that broke integration tests. Turns out that GCC and Clang disagreed on whether a friend of a subclass can see protected elements in the parent class. The local language lawyer decided that gcc was right, sent off a bug report to Clang, and I had to make my little unit test class a friend of the parent class as well. Maybe I was unlucky, but why does this sort of thing not happen to me in other languages?
In other languages I am consistently able to read up on the language syntax and features, implement things within my knowledge, catch my bugs with unit tests, and have a basically working system. I've had this experience with C, Lua, Perl, Ruby, Python, PL/SQL, Java, JavaScript, etc.
But C++ finds ways to astound and surprise me. Perhaps if I was a full-time C++ developer I'd learn all of the corners and would simply be productive. But the last time that I wrote a non-trivial C++ program, there wound up being multiple things which worked right in unit tests but not the full program until I ran Valgrind and followed suggestions that I would have had no way of figuring out on my own.
Yes, I'm aware of how easy it is for third party libraries to be bad. From dangling pointers in C to monkey patching in Ruby there is a lot of crazy stuff that can be screwed up by third party developers. But C++ is the only language where I had trouble not screwing myself up.
Phrased this way your concerns seem much more valid.
As for C++ file IO, I think it sucks too that something as idiomatic a iostream iterators are pretty much garbage. I hope they are removed in STL2 and they keep the good parts of iostreams and ditch the bad. With tellg and seekg you get the same or better performance as the c lib functions unless you need to care about visual studio performance... but if you are using that compiler you never actually compared enough about performance to benchmark.
I feel I must point at that C features shouldn't be expected to interact with C++ features. Printf does what it does, it was not designed to live with objects and types. It is a holdover from the C days. It is totally unaware of non-trivial types and does really gross things when you give it the wrong type. Using some other function to write to something that can be streamed or writing and operator<< overload for the the thing you actually wanted to output seem like the simplest approaches.
As for finding implementation specific bugs, you claim not to have found them in other languages, then included Javascript on a list of things you have used. Javascript is the poster child for implemtation specific problems, to the point where there are several sites that put real effort into describing differences between different implementations. This whole listing seems odd. These languages either have 1 implementation (Lua) so cannot have differences or are so under-specified that of course the implementations have huge differences (Ruby, Python, Sql). Clearly I have had more problems with all these then you I find all languages terrible at this point, I just a few to be less terrible.
I think I may know why you are shooting yourself with C++, as you put it. If you find RAII non-obvious after you have worked with it then there is definitely a problem with how you are approaching something about C++.
RAII, or deterministic deconstruction in general, is probably the single strongest thing the C++ language brings to the table. With RAII you can implement your own memory safety model via any kind of shared pointer you can dream up. With RAII you can prevent race conditions by creating exception safe mutex guards. Write your own transaction handler by putting the roll-back code in the deconstructor. With RAII you can clean up any kind of resource in a deterministic and safe way that few other languages offer.
I had to some work with automated UI testing recently (a complex application and framework with C++, Java, Ruby and Python). My application leaked resources in a very gross way because we had to pass handles to our resource back out to users writing scripts that could manipulate them. This leaky resource was whole web browsers.
For a combination of technical and business reasons the only suitable tool for creating browser instances. If I could have relied on Java's finalizers to be called I could easily have close them there. We found several situations where they clearly failed and much documentation about the reason they failed (and apparently how the JVM could be fixed if the standard authors were so compelled). After a couple of weeks of research and failing to be able to explain the various segments of the Java community the "using" keyword was inadequate for this usage pattern, the smallest hack we could come up with was a silly watchdog timer that checked the processes on the machine and knew when the web browser manipulation API was used. This was almost a 1000 lines of code to get right to buy nothing but resource safety in the face of exceptions. It would have been 4 lines of C++ and two of those would have been curly brackets.
Of course I am biased, I pick a story from my experience to suit my argument as you have done yours. I am still not sure how one hurts themselves more with C++ than particularly and if you have access to C++11, C++14 or C++17 it seems a fair bit safer than Java or Ruby because of the precise guarantees and strong tools for safety the language lacked before. Still can't keep up with With Rust or Haskell in the safety department though.
It is not that RAII is non-obvious after you've worked with it. It is that you can read through how the language works somewhere like http://www.cplusplus.com/doc/tutorial/, start producing software, and not realize that you have to do RAII. You can even, as Google did, have experienced and competent people write a large and well-structured program and then only belatedly realize that you can't use certain features because they didn't structure the program right.
There is a lot of that in C++. If you get everything right, then wonderful. If you don't, then that is a problem.
On implementation bugs, I have found implementation bugs in lots of languages. But not generally as things that I stumble over while proceeding with what seems to me like it should be the obvious thing to try.
With C++ it isn't like that. I gave you an example where there is a disagreement between compilers. But, for example, what happens if I supply an ordering method that isn't consistent? In other languages I get stuff sorted slightly inconsistently. In C++ I get a core dump. Good luck figuring out why.
On the complaint that you have about Java, that falls in the category of things that I expect to have to deal with. Part of my mental model for a language has to be the memory management rules. C++ lets you set up whatever you want. Perl does deterministic destructors but therefore can't collect circular data structures without help. Java has true garbage collection so it collects circular data structures, but it can't guarantee that they are collected in a timely way. JavaScript does true garbage collection now, but back in the IE 4.0/5.0 days they separately collected garbage for native objects and JavaScript objects with the result that garbage never got collected if there was a cycle between native and JavaScript objects.
This is one of the basic facts that I know that I have to understand about any language I work with. It is like pass by value vs pass by reference, or the scoping rules. I immediately look for it, understand it, and then am not surprised at the consequences. I see other people use the language for a while without trying to understand that. I understand their pain. But I'm not caught by surprise.
However C++ keeps finding new ways to surprise me. In the past I reserved it for cases where I need to implement an algorithm and squeeze and order or two new magnitudes of precise memory layout and performance beyond what is available in scripting languages. I've resolved that the next time I need that, I'll try a new language. My past experiences with C++ haven't been worth it.
Really like that I can create a class that stores all the knowledge of one concept internally and if I wrote that correctly I never need to look inside it again. Even better, if I document the contracts of using a class I can carefully optimize it and have broad performance effects with small code changes.
Things like std::string are just so much easier to work with that their C counterpart and things like std::filesystem::path simplify (or use the boost one if you don't have C++17 yet) so many things and doesn't even have a C counterpart. I point these out as simple examples but in all the code bases I have worked on there are similar examples, like most games a class to represent 2d and 3d points, which are used to define AxisAlignedBoundingBoxes, which are needed for collision detection algorithms which them selves need several classes to describe.
Then I can build systems of a size and complexity I literally could not comprehend without those abstractions. And then the compiler enforces them for me so other people can use them safely as well. Why is it so much harder to do this in C if C is so much "simpler".