I once heard that the C++ language contains 4 components: the first catalog is "C", the second is for OOP, the third is for productivity and flexibility such as stl and templates, and the last one is for special cases such as volatile, asm, etc. He then recommends to use catalog 1 with care, and avoid scenarios that one has to use catalog 4. Does that make sense?
This is fine if you do not plan to share your work with others, but it's not well-written C++. It will bite you later on. It's best to learn the C++ way of doing things. It will save you so much time and headache. Don't use character arrays, use strings. Don't use C arrays, use std::vector or std::array. Don't write your own lists or sets, use std::list/set or std::unordered_list/set. Don't use strcat when std::string operator + exists. Etc.
I personally rarely use smart pointers or make_shared/make_unique these days. I just don't need pointers. Most of the time allocation can be done without them, and when I need to pass things around I use references. There are exceptions for C APIs for cross-platform/cross-compiler work, of course. And sometimes library code needs it, ofc.
The STL and <algorithm> are your friend. They solve so many problems in a very elegant way. Learning them should be a priority.
I'd go easy on the OOP elements unless you know OOP programming very well. Just using classes as containers for data and functions is more than fine for C++ most of the time.
Writing your own templates can be a bit of a footgun until you understand them. Feel free to put that off awhile.
Don't mess with volatile and asm unless you are 100% sure that what you're doing needs it.
Also: Be cautious with use of auto. A bit here and there is fine, but too much and code can become unreadable. C++ is a typed language for a reason.
If that paragraph doesn't make any sense, and you think you need volatile then there are basically two possibilities: You're writing a Java program (which uses that keyword for something else), or you need std::atomic (or __sync_* for C) instead.
Actually even C has _Atomic these days!
Yes, although one place where "auto" should almost always be used is to declare iterators (not that one should be needing them so much nowadays), and I think harmless for range-based for loops "for (auto i : v)" although as you say there's definitely a convenience/readability trade off.
Newer languages and modern C++ favor composition instead. You define interfaces that provide some well-defined capability, and then you write things that wrap the interfaces to provide additional functionality. In C++ you can use templates to do this without any runtime overhead. In C, you can either use preprocessor macros (ouch) or you can build your own vtables. The vtable approach adds virtual method invocations all over the place, so it's not zero cost.
The C++ approach actually isn't zero-cost either: You can end up having many copies of the same template logic, which blows up your instruction cache. One of the big innovations of swift was to avoid that. As far as I know, Rust macros and "go generate" produce binaries that are closer to the C++ approach.
Anyway, especially for emulators, you should look into getting good with C++ template meta programming, or just learn rust and then use its implementation of generics. Both approaches will let the compiler inline the heck out of stuff that ends up in the inner loop. In particular, clang + gcc are both good at constant propagation.
One problem with jumping straight from C to rust is that you basically have to already be able to write stable C++ code in order to get it to compile at all. The borrow checker moves subtle but common C++ errors from runtime to compile time. If you have a lot of experience with C already, the jump might be OK.
(edit: I should add that C++ isn't standing still, and there are lots of cool efforts to backport the good ideas from Rust to it. Systems language competition is a good thing, and they're my two favorite languages!)
linkers have been able to perform identical-code-folding optimizations for a few decades now
Without having to squint, 12 of those languages are easily categorized as OO languages. Given the mindshare of those 12 languages, I don't think it makes sense to say that "OO programming is mostly frowned upon." [emphasis added] Maybe it's frowned upon by some, maybe even many, but if it's mostly frowned upon then a lot of people must hate their work.
Only in certain circles. For the software world as a whole, "mostly" is rather an overstatement. (For that matter, for the software world as a whole, "mostly" is an overstatement no matter what claim follows the "mostly".)
> OO added the idea of implementation inheritance to interfaces, and that's mostly a bad idea.
There is more than one flavor of OO. Not all of them support implementation inheritance. You're using a feature of a sub-part to complain about the whole. (In fairness, though, this is a thread about C++...)
Current best practice is "prefer composition over inheritance". There are places, though, where inheritance is the correct answer. When you hit those places, use it. Where it's not, don't use it.
Thank you in advance!
1) The major part of C to avoid is raw pointers and malloc, and generally anything where C++ has a more modern alternative. Don't use C datastructures (pointers, strings, arrays) where C++ replacements exist (smart pointers, std:string, std::array and std::vector, etc), or use C libraries where C++ replacements exist (e.g. C++ std::string vs C's string.h).
Of course you can't avoid all of C, since the syntax of C++ is an extension of C.
2) I wouldn't characterize what C++ adds to C as OOP. OOP is a design methodology, whereas the main addition C++ gives you is classes which are better thought of just as powerful and convenient type of data structure.
The core feature of classes you always want to use are constructors and destructors. Any initialization of the class's data members should be done in the constructor (don't leave things uninitialized), and any final cleanup (releasing memory or locks, closing files, etc) should be put in the destructor so that it always happens (even if your program throws exceptions).
Don't feel that just because classes support subclassing, polymorphism (virtual methods), etc, that you should be using them. They are there in case you need them, but if in doubt don't.
3a) The STL is just the standard library for C++. You should always be using STL data structures (std::string, std::list, std::vector, std::map, etc) when applicable - not just "for productivity".
3b) Templates (template classes, constructors/methods, functions) are not needed for most everyday use of C++. They are there for library writers, and on occasion for writing your own class and libraries. Think of them a bit like class inheritence - they are there in case you need them, but not something you should be reaching for unless there is no better way.
4) C++ has a LOT of stuff (esp. libraries) that might be considered as "for special case use only". A rookie mistake might be to think that C++ has all this stuff - I should be using it! In general you should ignore the obscure stuff, and only use it when some special circumstance requires it.
The Standard Template Library is Alexander Stepanov's generic programming achieved via the relatively new (at the time) C++ Templates feature. At this point (the late 1980s through early 1990s) Generic Programming is an obscure academic idea, it's not how normal software works. Stepanov is persuaded to present his library to WG21 ("the committee") in 1993 and their work is eventually standardised as C++ 98 a few years later.
The most important part of the STL is the algorithms, generic algorithms are an amazing idea. The collections, eh, they're nothing to write home about, there are a dozen takes on the iterator problem with different trade-offs, but this idea of generic algorithms unlocks so much power and that's why lots of languages grew generics or for new languages had them on day one.
Just tested, works fine with Safari (mobile, but desktop usually has the same behavior).
Chrome's attempt to use a secure connection resulting in 404 while the actual link works fine isn't great. But it's understandable and the TLS-first assumption the're using probably works just fine in the other 99.999% situations.
If only they'd taken the time to copy the http config and setup let's encrypt or cert from GEANT Vereniging CA apparently preferred by rug.nl...