6 ms·
Sorry if it is a bit off-topic. If you just started learning C++, why did you choose it instead of another language? (Rust, C#, Go, etc) I know a bit of C but
by slekker 2y ago
Sorry if it is a bit off-topic.
If you just started learning C++, why did you choose it instead of another language? (Rust, C#, Go, etc)
I know a bit of C but feel that the sheer "thickness" of C++ is too daunting and scary to even start.
- npalli 2y agoThe most complex, demanding and cutting edge computational fields - Machine Learning, Artificial Intelligence, Real-time multi-user Gaming, High frequency Trading, Rendering/Animation, High Performance Computing, Compiler infrastructure (LLVM) - are all at the core written in C++ for the most part. There is no other option in the foreseeable future as the investment needed to rewrite (if you can find the people) is in the $100's of billions. So you will need to know C++ if we want to be the cutting edge and need extreme performance. On the other hand, if you don't need these "hard-core" features then any language will do. In fact, most of these have Python or other language interfaces so you don't need to know much C++.
- tialaramex 2y ago> So you will need to know C++ if we want to be the cutting edge and need extreme performance. I would suggest a better phrasing might be that you should learn C++ if you want to cling to existing software in the state it is today, certain that history ended yesterday and the future is just the same forever from here on. You won't get "extreme performance" from C++ because it is buried under the weight of decades of compatibility hacks.
- slekker 2y agoA more extreme version of this would be COBOL right? Even if people stopped writing C++ today the amount of code that's already written will last many lifetimes.
- tialaramex 2y agoSure, I do not advise people to go learn COBOL either. In fact, I never learned COBOL, they were writing COBOL at the first place I "worked" as a teenager† and it was clearly not the future. † in the UK there was a discrepancy between what happens to the sort of teenager who exhibits talent and interest in an area like writing software, who is sent to just watch adults doing that and mostly doesn't do any actual work themselves as "Work Shadowing", versus those whose direction seems more... manual who are expected to actually go do stuff in the same period, supervised by adults of course, but still very much doing the actual work, "Work Experience". This seems very obviously unfair, although of course as the teenager who wasn't expected to actually do much I wasn't complaining at the time...
- boppo1 2y agoWhat is the future?
- tialaramex 2y agoWhat is the future now? Or what was the future when I was watching grown-ups programming in COBOL over thirty years ago? Thirty years ago the future was C++. How did that work out? Seems like it was pretty popular, this thread is about the third edition of a book about it.
- CyberDildonics 2y agoI don't even know what you are trying to say here. C++ is great to program in and has a fantastic eco system of tools and libraries. It is something you can safely base a business around. You won't get "extreme performance" from C++ because it is buried under the weight of decades of compatibility hacks. This doesn't even make sense. What is an example of something that can't be fast because it is done in C++? What "compatibility hacks" are slowing programs down? This does not sound like something someone with experience in C++ would say.
- tialaramex 2y ago> This doesn't even make sense. What is an example of something that can't be fast because it is done in C++? What "compatibility hacks" are slowing programs down? Let's look at two very different perf leaks in ISO C++. Firstly move assignment which is right at the heart of the language. Initially C++ doesn't have move semantics at all, which is a problem because in a bunch of cases that's key to "extreme performance". So in the "lost decade" period between C++ 03 and C++ 11 considerable work was done to figure out a way to unlock this, but of course C++ insisted on backwards compatibility with the code written for C++ 98 with no such semantic. The result is that the actual move semantic people wanted can't quite be done, this is now called "destructive move" and proponents of the compatible option C++ 11 and later had claim it's equivalent to the move they delivered, plus delete. But that's... disingenuous. The C++ 11 move is actually (move + create), so to build "destructive move", when that's what you need, you must write (move + create) + destroy. Sometimes the compiler can see what's happening here and emit the same machine code you'd get in a language with native move semantics, but sometimes it has no way to figure this out, and you're emitting move + create + destroy, which is markedly slower as well as of course being more error prone. Secondly right up at the surface, where we can feel the rain, and appropriately something Bjarne Stroustrup (author of the book we're talking about here) has noticed himself, the provided growable array, std::vector lacks the bifurcated reservation. Vec::reserve_exact isn't enough, you need Vec::reserve as well for good performance with a growable array API, but C++ doesn't provide this, it provides only Vec::reserve_exact under the name "reserve" and there's no room to offer both in the compatible API, which means as a user/ application programmer this fundamental type is a small perf leak. Bjarne shrugs this off, oh well, just don't use the reserve API to get performance benefits. But everybody else can do so, this choice means C++ is leaving it on the table for somebody else with a better growable array type. Finally though, I want to look at a beacon over the horizon, where "extreme performance" really is something they're thinking about. Iterator Loops (sometimes "Chunk Loops") are a technique where the language lets you directly express in your definition of a loop how it can be performed in a SIMD-fashion, so e.g. you write the code to search an N byte buffer for the byte you're looking for, but then revisit that loop and also write code for searching N=M*16 bytes, using 16 bytes at once. This lets you write, in a high level language, code which will be easy for a compiler to SIMD accelerate without fragile idiom recognition. C++ of course does not provide Iterator Loops and instead you'd reach for manual inline assembler in these cases today.
- spacechild1 2y agoI started because I became interested in graphics and audio programming. Audio plugin development in particular is completely dominated by C++.
- cuanim 2y agoDo you have any recommendations for someone interested in audio programming?
- spacechild1 2y agoPersonally, I started by writing externals for Pure Data, then started to contribute to the core. Later I took the same path for SuperCollider. You may start with simple audio plugins. Have a look at JUCE (https://juce.com/ https://juce.com/)! Realtime audio programming has some rather strict requirements that you don't have in most other software. Check out this classic article: http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing http://www.rossbencina.com/code/real-time-audio-programming-...
- cageface 2y agoThe Will Pirkle books are good.
- jandrewrogers 2y agoThere are still some high-performance software domains where (modern) C++ is unambiguously the best tool for the job. Database engines are a good example of this, they pervasively break the compiler's understanding of object lifetimes which requires flexibility in the language that C++ can explicitly express in an ergonomic way. No one learns all of C++, you just need to learn the bits that are useful for the kinds of applications you write. If, for example, you are building database kernels then you are unlikely to use any of the STL containers (even std::array and std::vector are infrequent) in most of the code. However, you will need to know how to manually fix-up object lifetimes using semi-obscure language features you would never need to know about for most server apps. If you stay within a relatively narrow application domain, the useful parts of C++ for that domain crystallize pretty readily in my experience, which is much easier to learn.
- jstimpfle 2y agoI would be interested how you "fix-up object lifetimes"?
- jandrewrogers 2y agoSure, it is pretty simple, just esoteric. The compiler attempts to track object lifetimes for the purpose of optimization e.g. if the object contains a notionally immutable value it doesn’t have to re-read the value during the object’s lifetime. A lot of compile-time code optimization is based on knowing when an object at a memory address is changed or destroyed. If the objects don’t get destroyed but merely disappear, or worse, are replaced with a different object at the same address, and the compiler can’t see that at compile-time then the compiler assumes it doesn’t happen. This violates strict aliasing rules in C/C++ even though there are legitimate reasons for this to occur. C/C++ systems code, like Linux, commonly disable strict aliasing rules because it causes undefined behavior, even though it also disables certain optimizations. In the last several revisions of C++, they have added blessed methods of informing the compiler when these object lifetime rug-pull situations occur, so that it can optimize around them without disabling the optimizations enabled by strict aliasing. This includes functions like std::launder, which acts like a constant folding barrier i.e. the compiler can’t assume that constants at that address prior to the barrier call are still operative when generating code. There are a couple other functions in C++23 that explicit take a memory address and explicitly start a new lifetime with an arbitrary type, without constructing a type at that address; these are no-ops, all of these functions are compiler annotations, they don’t generate code. These are blessed ways of doing more hack-ish ways of effecting the same result in recent versions of C++ (e.g. the memmove/launder trick). In old versions of C and C++, the ways of doing this were technically undefined behavior but the compiler writers unofficially provided ways to work around this that would behave as needed since it had valid use cases, which is not a great way to work. This doesn’t just affect lifetimes, though that is most of what the fix-up is about. Mutability of references is similarly fuzzy and it is impossible for a good design to guarantee that multiple mutable references don’t exist, so you need other mechanisms to guarantee they never conflict. However, these fix-ups are above the level of the compiler. In the extreme case of database kernels, most objects have an ambiguous lifetime and uncertain address. Consequently, you have to create object reference wrappers that hide what is required to ensure strictly defined behavior in these cases and to ensure conflicts can’t happen. Wrapping your object references with some small hygienic functions can eliminate the issue.