Modern C++ Programming Course
github.com
github.com
I've had great success using ChatGPTv4 to help me write modern C++ that works with CUDA, using prompts like these. (I have not attempted to get it to write parallelized code given loops/serial code as an input):
> Please convert this Rust code to modern C++, compatible with the latest version of the nvcc CUDA compiler: ```rust ```
It will output a compilable/working result, and explain each of the language differences in question. It will make sure to use `std::*` instead of the more rigid C-derived equivalents when able, and take advantage of looping over array pointers etc, vice i++ loops. `auto` var types etc.
> This open-access course is directed at those who are already familiar with C
> and object-oriented programming towards a proficiency level of C++
> programming.I agree with Kate Gregory that this is a bad way to teach C++ from scratch. That is, if you know only say, Python or Java (or nothing) and want to learn C++, you should not begin by learning C. Kate's approach skips many of the things you can do in C++ but you shouldn't, whereas if we try to start with C you're going to see that a lot, because "they were legal in C" is why they're allowed in C++ even though they're a bad idea and then you have to unlearn things. You're maybe expecting some of that if you've years of C programming experience, but there's no need to introduce an idea on Monday only to tell students on Tuesday that it's a bad idea and they must never do that.
The most insidious cases are where something is legal and correct in C but it's wrong in C++ yet it will compile and you maybe have broken software. There are some nasty type punning examples, where the pun was an idiomatic C expression which does exactly what you wanted, but in C++ that's Undefined Behaviour and all bets are off. You'd just never teach those type puns in a pure C++ course, they're never the Right Thing™.
I definitely think Bjarne Stroustrup's book about his own language isn't very good, even in later editions (which correspond to a more modern language) and so I would avoid buying that, I'm not sure it's a good defence of the language as an idea and I'm sure it isn't an effective tutorial, even if not for being out-of-date.
I always look askance at folks who say they know C++ but not C. The C++ abstract machine is built over the C abstract machine and it becomes even more clearer when you go down to the binary level.
Understanding C idioms, the standard library, best practices, and general C software architecture , is less important if not downright negative early in your formation. You will end up picking a lot up anyway if you stick to C++ long enough.
"Less important" maybe but not "negative".
You have to have a decent C base (not necessarily expert level with knowledge of dark corners/tricky idioms/etc.) before you start with C++. One example is being comfortable with raw pointers. I often see "Modern C++" proponents say you should never use (and by inference learn) raw pointers which is absolutely counter-productive. It is also easier to learn C++ as a "better C" in the beginning else it becomes overwhelming. I believe this is the main reason most beginning C++ programmers find the language "scary/difficult/huge/overwhelming/confusing". They are trying to learn everything at the same time which is an impossibility with a language as baroque as C++.
However there is a huge amount of C code and programmers who would like to move to C++ and it is for them that the techniques of C coexisting with C++ are very relevant. There can be no wholesale rewrite of the code into C++ but a gradual rewrite module by module and as needed. Using C++ as a "better C" is the path here.
But this isn't so much like C, where raw pointers often express ownership.
You aren't going to really learn "everything" in C++ anyway, regardless of how you approach it, the language is a vast sprawling mess, the fact somebody wrote a serious book just about initialization [https://leanpub.com/cppinitbook] in C++ gestures at the problem. Freeing themselves of the need to have a language which is well-defined, or which can be demonstrated to be sound, or really follow any principles whatsoever was doubtless briefly convenient but the result is unmaintainable nonsense.
As a diehard proponent of Rust your views on C++ are well known and there is nothing new here. But the fact of the matter is that the industry runs on C/C++ and the main reason is due to its baroque set of features whatever one may think of them.
There are resources oriented toward embedded C++ that address these (at least memory allocation.)
On a project a couple years ago I was pushing to use C++ instead of C, if only as a "C compiled using the C++ compiler" for better type checking. I could not convince the project lead, who's technical depth far exceeded mine, that the C++ compiler was as likely as the C compiler to produce correct translations.
If you want to write bare metal C++ then this page from the above tutorial will be useful https://www.avabodh.com/cxxin/nostdlib.html
2) Software Architecture with C++ by Adrian Ostrowski and Piotr Gaczkowski. - Gives the overall picture of how to use C++ plus relevant modern tools as a complete development system.
3) The C++ Programming Language by Bjarne Stroustrup. - The bible/reference with programming techniques for the language.
Learning C++ is not difficult and don't let the size of the language intimidate you. Survey the different ways of programming in C++ i.e. Imperative/Object-Oriented/Generic/Meta-programming and use them as needed in your project without trying to master everything; that will only happen over time as you gain more experience.
For my target space, there's a few rules for c++.
Footguns: A. No STL, it causes to much bloat when binary size is critical. B. (almost) No inheritance or virtual functions. Again, it causes some bloat and adds in some instructions and code to support these features that can cause issues in low level environments.
Things to learn (All work in the kernel):
A. Learn templates, especially c++20. Templates add ZERO bloat, they literally just generate the function again with proper types the same way a macro would.
B. Use RAII.
C. Use constructors and overloading.
D. Zero pointers should be exposed to code except where absolutely needed. If you need to pass by reference, use the c++ style.
E. All allocations should be wrapped in a class with RAII. You can overload the operators on the class to make it seem like a pointer so you can still do if(!RAIIPointer).
A good video on kernel c++ is here https://www.youtube.com/watch?v=AsSMKL5vaXw . You can use a surprising amount of C++ language features in the kernel and it makes it extremely smooth and safe if you do it properly.
You can do some nifty stuff like generate CRC lookup tables at compile time without hardcoding them.
I also think you are a bit harsh on virtual functions - it introduces a single indirection, yes, but sometimes that is fully justified. RTTI on the other hand... of course depends a bit on target characteristics.
Perhaps controversial, I've also found (especially bare) lambdas and even std::function objects useful, although may evolve into something purely static when the dust settled. Highly dependent on target of course.
It will be interesting to see the final form of the new MISRA std, since the active one predates all of this.
std::vector
std::list
std::map
std::unordered_map
std::set
std::unordered_set
std::sort
std::transform
std::merge
std::string
std::regex
std::swap
std::function
std::stable_partition
But there are much more than that in STL.
> A. Learn templates, especially c++20. Templates add ZERO bloat, they literally just generate the function again with proper types
"Avoid STL due to bloat but embrace templates" doesn't make sense to me. Isn't that exactly what code bloat is? Too much code generation?
In general, also, I have found that it is wise to learn C++ socially - i.e. participate in Open Source projects, as you learn/study/contribute/assist other C++ developers, on a semi-regular basis.
I've learned a lot about what I would call "decent C++ code" (i.e. shipping to tens of thousands, if not hundreds of thousands of customers) from such projects. I would suggest finding an open source C++ project, aligned with your interests, and study the codebase - as well as the repo history (i.e. gource) - to get a productive, relatively effortless (if the interests align) boost into the subject.
(My particular favourite project is the JUCE Audio library: https://juce.com/ .. one of many hundreds of great projects out there from which one can also glean modern C++ practices..)
Note for those who are not used to C++Now talks: they are intented to be a bit more informal with regular interjections from the audience (who at C++Now are also often heavily involved in the development of the C++ standard), so don't think people are being rude by jumping in!
Should "modern" C++ even use new/delete? I'm a C++ n00b, but I thought these can be avoided entirely now.
It's still useful to learn about the concept when dealing with old code.
I also note a number of the possibly-ambiguous c-style casts in examples, despite already having mentioned the explicit versions (static_cast and the like).
Plus there seems to be a fair bit of system & machine dependent stuff mentioned like it's /always/ true - like stack being at a "higher" address space than the heap and code sections, or the stack growing down. It also says that the Data section is "slower" than the stack which... isn't true? If they're spilled out of registers, they're likely functionally identical? Or at least for small microbenchmarks depend on specific implementation details, like how the pointer to the object is calculated and dereferenced.... And object size and cache interactions... And a million other things...
And that's just the first few chapters I looked at :P
In my experience, every useful C++ application requires wrangling some historic smart pointers implementation: Boost, Unreal, libwebrtc, Qt.
Even NVIDIA uses its own smart pointers (thrust::device_ptr) though that's understandable. Also there's stuff like this: https://stackoverflow.com/questions/65938991/how-to-use-lamb... for e.g. TensorRT.
It's definitely useful to learn about "new" and "delete", because those are the primitives that memory management is built on top of. But it should be followed up with good advice like, rarely use these in practice. You should almost always be using unique_ptr or shared_ptr instead of new'ing up pointers that you intend to explicitly delete later.
I really wish there was a thread unsafe version of shared pointers, without atomics overhead, in the standard. Maybe without weak pointers.
What exactly would you use these for? I find that usually I can get away with unique_ptr for the sort of object that I have many of where pointer performance matters.
https://cdm.link/2021/11/watch-larry-cuba-explain-how-he-ani...
Implicit type conversion rules, applied in order, before any operation: ⊗: any operation (*, +, /, -, %, etc.)
(A) Floating point promotion
floating type ⊗ integer type → floating type
(B) Implicit integer promotion
small integral type := any signed/unsigned integral type smaller than int small integral type ⊗ small integral type → int
(C) Size promotion
small type ⊗ large type → large type
(D) Sign promotion
signed type ⊗ unsigned type → unsigned type
Edit: oops, I missed the explainer. The ⊗ stands in for any operator in case that was confusing to anyone else who missed it. :-)Either way the C++ dependency management situation even makes the Python dependency management situation look good by comparison.
Is there a better way than “script the compilation of all dependencies and share the result” for any big project that has to support Windows? I’m interested in alternatives.
Basically I'd prefer to have a docker image with tooling that I can hook into.
I don't do this because I have to, I do this because I prefer to keep non-system -critical software managed by non-root users and separated from the systems rootfs.
On your common desktop Linux distro, I think C and C++ toolchains are the least difficult to setup and use without a container though (for me). On Gentoo I can just emerge gcc or clang and enable whatever USE flags I want, and they are installed and updated automatically with the rest of my system.
I use the Gentoo system package manager to manage my Rust toolchain as well instead of using rustup, so that it behaves like described above, it's updated and managed automatically and with the rest of my system!
I do realize that many distros have issues with software being out of date though, and that is a big problem! With Gentoo I can install multiple versions of most things in parallel and can very easily package anything that doesn't exist yet.
Also to clarify, I use the system package manager to build and manage my containers, this is how I use the system package manager to manage Rust's toolchain but also have it inside of a container. All of my containers are just nested Gentoos that I can install stuff into with the system package manager. I can also install a package manager into the nested Gentoo and build/install stuff while "inside" of it.
The thing is, you don't need to do this with Rust as far as I can tell. There may be some benefits, but ultimately your project can easily specify its own compiler version, its own target directory (the default is per-project), etc. There are some shared resources like caches, which you can split if you want to.
I can see why you'd still do this - but, the main reason would be... if you have dependencies on C/C++.
In my experience, the hard part is rigorously controlling the libraries a build uses. Using CMake, it's easy enough to add libraries to a build, but harder to stop the thing going off and looking round /usr/lib64 and so on. On my physical workstation, there is all sorts of stuff in there, because i have a desktop environment and a cornucopia of tools installed. I don't want a build using any of it! If a build needs a library which i have not explicitly added, i want it to fail, not use something from the system. But between default paths and rpaths in libraries and so on, that seems hard to do in a watertight way. I've done endless fiddling with sysroot flags, but i'm not sure it's not leaking. A container takes care of all that in a very definite way.
It is surprising how many people look surprised (that also claim they know the language) when you tell them that code in .cpp does not get inlined into other .cpp files no matter what doing compilation. (yes the linker can (and should) do that with LTO doing linking)
The linker doesn't inline anything, LTO/LTCG is about running (part of) the compile process at link time. But that's really no concern for the C++ code but an implementation detail of the toolchain - you could just as well not have a separate link step and instead have the compiler process all compilation units in one step.
I get that it is just an implementation detail, but so are many things in C++ and you usually care about these things otherwise you would not be using the language in the first place.
Many projects also disable exceptions that is also an 'implementation detail' (or at least something that is definitely not required by the standard I would imagine), but now you are technically not writing C++ anymore.
I guess this is also one important thing when learning C++. The community is very fragmented, and there seems to be disconnect between C++ users and committee.
C++ is here to stay for a very long time.
Memory safety is absolutely important in certain kinds of games. At least, as a player, I want games to not be exploited for cheats, and I don't want progress lost when a game crashes due to memory issues.
All that said, I would agree that if you want a job in games, learning C++ is a better idea than Rust right now.
Kinda average in game development and sadly pretty low in embedded systems.
All way less common than your average Python position, but probably way more interesting.
I've always heard that they're currently mostly using C++ (and sometimes Java). But I'm not sure how dogmatic or change-averse they are on average.
Having spent the better part of the last decade writing go though, I think C++'s syntax is a bit too cluttered.
(You might have to jump through some links)
Also, fancy seeing someone else from RuG here :)
"Every second spent trying to understand the language is one not spent understanding the problem"
Did a lot of work in LaTeX the last few years and they make C++ looks like something made in heaven
Is anyone using it for new projects?
In fact the question should be: what interesting projects don't use C++?
For some very subjective definition of intersecting of course.
I'm currently doing some backend work, and I really miss it. I don't think I've done anything interesting algorithm-wise since I switched. Alas, the pay is usually much better in SaaS land.
> Modern C++ Programming Course (C++11/14/17/20)
pdftk *.pdf cat output Modern_Cpp_Programming.pdfTable of Contents?
LOL, yeah I think we can stop spending time on this (which was quite funny back in the day).
I am not saying that this isn't important, but learning about pointers and references is totally useless unless someone shows you why you would use them, where you would use them etc.
Like you can basically hack your way through learning Python or JS. I didn't learn Python from a book, for sure.
But with C++ and Rust that's not an optimal strategy. You have to do both -- do practical projects, and actually study it a bit.
There's also a huge amount of disagreement about C++, so I think it makes sense to start with a codebase you want to work on, and then ask the people who WROTE that codebase what C++ books and learning materials they like.
e.g. Game C++ is kind of different than Google C++, but both are good (they get work done, and multiple people can work together in that style). There is a lot of really bad C++ out there. The gulf between good and bad C++ is bigger than good and bad Python or JS. You want to learn from experienced people who get things done, not language lawyers
or pascal.