My Rant on C++



Origami Bulldoser says:

Passing error codes down 20 levels of stack rather than throwing is a good idea?

Jether B. Strong says:

cpp is more like a high level assembler than a high level programming language. After learning python I don’t see a real reason to go back to cpp

richtw says:

Agreed with a lot of that. As a professional game developer for nearly 20 years, working with C++14 and enduring build times of >20 minutes every time I touch a core header, I’d love to take a step back away from the increasing complexity of C++ and look at things in a less abstract and more pragmatic way.

Apart from the injection of ‘invisible’ code through constructors and destructors (which can make code far harder to reason about), the language encourages you to forget what’s going on at the low level with regard to allocation and suchlike (there was some recent revelation that Google Chrome unwittingly makes 25000 allocations every time you press a key!). The OOP model is outdated, and excessive dynamic dispatch, particularly in loops, has a profound adverse effect on performance, as I’ve discovered on a number of occasions.

Having also gone back to pure C for personal projects (I thought I was the only one!), I certainly find myself missing certain C++ features, and I too have mused on how a new language built on C might look.

I’ve also found myself pulled in the completely opposite direction – that of functional programming. While it might not really be an appropriate paradigm for games or low-level programming (from a performance perspective), something which appeals to me is its application of immutability and value semantics in order to trivially leverage parallelism. I would predict that in the next 10-15 years, PCs with 32+ cores will start to become commonplace, and we developers are going to have to embrace development for multiple cores as a given, and the more that any language helps out with that, the better.

I don’t suppose there’s any clear way to reconcile functional idioms and C’s strictly procedural medium-level approach, but it’s interesting to wonder if the best of both worlds could be taken, and what kind of crazy language that might look like. Encouraging use of value semantics by default might be an interesting area to look at, leaning on the optimizer to turn pass-by-value into pass-by-reference unless the passed value is mutated by the callee. C also needs something like lambdas, in order to be able to match the performance of C++ in certain kind of generic functions, where the optimizer can inline the lambda instead of it being pulled out as a separate call-to-pointer-to-function.

As much as I love C, I still can’t imagine a large-scale multi-developer project using it these days. Add multithreading and memory management into the mix and I can’t imagine it scaling; I’d be happy to persuaded otherwise. C++ definitely isn’t the right way for me though.

Hy Che says:

Sorry for my nooby question, Im learning programming. You said that the error can be handled by returning the value of the function. But if you do that way, how can you get the actually used value for other stuff not for handling error ?. Thanks for great video.

Leo S says:

Good points, but to be fair, C++ really is an easy target to rant about its problems.

TheBuzzSaw says:

Have you looked into JAI by Jonathan Blow?

bpunsky says:

Maybe you should take the extra step, and do a tutorial series on compiler programming, building your own language along the way. Coding a compiler is actually much easier than you might imagine, but there are very few accessible resources out there on doing so. Some ideas for your consideration:

Step 1) Define your language, ideally as a context-free grammar.
Step 2) Create an AST framework capable of representing your language, with different nodes for each production.
Step 3) Build a lexer/tokenizer and parser that transform your raw source code into an AST.
Step 4) Finish the compiler with a code generator that transforms the AST into target code.

The lexer/tokenizer is dead simple, and you can probably get that built in one video. Parser, two or three more.

The target code could simply be C++ to start with, which would be easy to implement, and if you were to target LLVM IR you could use Clang to compile to machine code. Or you could get fancy and create a virtual machine with its own byte code, and generate that byte code.

To keep things simple in my own project, I had the AST nodes double as tokens. So, the lexer generates AST nodes from the source code, and the parser assembles them into a tree structure.

I’d start with a simple language, small in scope, so that you can show more up front. Once everything is working and you can compile, then you could start expanding and adding new features.

Francisco Paisana says:

Regarding his criticisms of RAII and why defer is so much better: I don’t like the noise it creates in the code. Still, if I want to use something other the default ctr/dtr, the language should provide that functionality, which C++ actually does.

And C++ will soon provide the tools for the next examples he mentions on static duck-typing. Check “constexpr” and “concepts”. No need for a new language just bc of those features.

hymen0callis says:

In C++, there’s the _SCOPE_EXIT_ macro made popular by Andrei Alexandrescu or _Boost::ScopeExit_, which do basically the same as _defer()_. I’d prefer a built-in keyword like that though.

Admittedly, I’ve never been a C programmer and I’d never want to program in C when I can also do it in C++. C++ (done right) is *so* much more elegant [1], sophisticated and capable in my opinion. The sad thing is, there’s too much backwards compatibility in the language and many newer language features aren’t yet implemented by some compilers (MSVC), and there’s also that _consistency_ problem you’re alluding to in the rant: too many ways to do the same thing.

[1] Of course, this is a matter of personal preference.

RockTo11 says:

I think Objective-C is what C++ should have been. It’s a shame it’s not that portable, since most of the functionality is in the libraries. It’s a clean (arguably simple) layer on top of C, with a mostly consistent syntax. I also quite like the names arguments in function calls.

SoulofAnotherDeity says:

My suggestions to improve C:

– Optional return types for functions. If it doesn’t have a return type, it’s void.

– The ‘.’ operator should dereference pointers. No excuse for ‘->’.

– A function with a pointer-type argument should automatically reference a non-pointer object. No excuse for & everywhere.

– Add in C++11-style for-each blocks `eg. for (arg : args) { … }`

– Simplify the terminology a bit so you don’t have to type as much. switch->on, break->exit, continue->next. This seems like an odd suggestion, but you’d be surprised just how good it looks.

– Allow the ability to continue or break out of loops by the name of their iterator.

– Add a transparent string data type.

– Allow symbol capturing on functions and blocks of code. eg. `int open(str path, int mode, int perms) [errno] { … return 0; }`

– Rewrite the entire api. For the love of all that is holy in this world, get rid of that abomination and standardize the things that literally everyone uses these days (threads, audio, graphics, input, localization, big numbers, etc.) I’m absolutely fed up with having to write wrappers around 4 or 5 platform-specific api’s every time I want to write a portable application.

– Add the ability to compare with, assign to, or iterate across slices of arrays or strings. It’s like an incredibly terse and OP implementation of strncmp and strncpy.

– Operator and function overloading

– Namespaces/modules/packages

– Standardize anonymous enums, structs, and unions. Seriously.

– Declaring an enum, struct, or union should declare the type of it as well. Only imbeciles (read “POSIX”) are dumb enough to think that people like typing ‘enum’, ‘struct’, and ‘union’ everywhere.

– Don’t let enums pollute the global namespace unless they’re anonymous. And if structs or unions are anonymous, pollute the hell out of it. My intentions are clear.

– How about a ‘countof’ operator that does the equivalent of `sizeof(x) / sizeof(*x)`?

– Screw the last idea, why not get rid of all *of operators and have meta-attributes? `xsize; xtype; xcount; etc.`.

Zeratul Zum says:

Guy, just say you don’t like it and stop the bullshit.

instant_apples says:

As someone who has been using C++ heavily for many years, I think I might be able to contribute here.

A) Exceptions are a vital part of software. Error codes encourage a heavily procedural style of code, which is not always suitable. Exceptions allow errors to be handled in a generic, automatic way, so when a team member is writing code, they can safely assume that no errors are silently ignored. Beyond that, error codes are slower than exceptions in the non-exceptional case (exceptions trade space for time).

B) In my years of using C++ professionally, I have very very rarely (like maybe twice) seen a constructor that can fail. Even then, you wouldn’t write the try-catch directly around the object construction. That entirely defeats the purpose. The exception will usually be caught higher up.

C) Do you honestly want to be writing “defer destroy_thing()” after every call to “create_thing()”? What if you forget? What if a team member forgets? Memory leak, deadlock, or worse. What if the object is destroyed too soon? Destructors serve the exact same purpose as defer, and are automatically called, with no room for human error, and they don’t clutter your code. (Although I do use a “defer” macro when working with OpenGL because its resource management is barbaric.)

D) I don’t understand how your “static duck typing” example is different from templates. One less line of code? Regarding OOP, it’s just another style of coding. C++ doesn’t force it upon you, it’s just there if you want it. People coming from a Java background will probably want OOP, while someone coming from OCaml can just pretend it’s not there. I’ve worked on several C++ projects that don’t use inheritance.

E) In my experience, move semantics operate seamlessly with the language. I can now return an array from a function without copying it, and not once do I have to type “&&”. In fact, I almost never type “&&” because moves are mostly implicit.

That’s all. There are a lot of things I dislike about C++, even more than you gave, but I have to disagree with most of your points here. I just get the feeling that you never really gave most of these features a chance, or never worked on a large team.

Thanks for reading this far.

FyberOptic says:

I cut my teeth on Basic and Qbasic as a kid, moved to Turbo Pascal for a few years as a teen, then finally to C and C++ by the time I hit my late teens/20s. I spent a large portion of my adult life with the C languages, thinking that’s just what programming was. There were various other languages in there too, mind you, from assembly to Javascript, but C/C++ was still the go-to language for actual applications.

But when circumstances eventually thrust me into Java, the difference on efficiency was mindblowing. You go from fighting a compiler and cryptic errors on a regular basis in C++ to simply dealing with your own occasional mistakes or lack of imagination in Java. Making one mistake doesn’t cause the compiler to shit itself with a hundred errors to sort through. Your Java IDE quickly and immediately shows you the source of a problem as you work due to real-time compilation and you fix it in a matter of seconds. The package-oriented nature of Java also makes it naturally more organized and easier to manage. Code hot-swapping lets to alter code while your application is running to quickly perfect something. You can refactor a field/method/class name in a large project with almost zero chance of it screwing up, where as Visual Studio rarely works properly. You can properly search for all references to something and it intelligently does so, where as Visual Studio shows you anything with that name regardless of whether it’s relevant. The Eclipse/Idea/etc equivalent of Intellisense is order of magnitudes better than Visual Studio.

And that’s the thing. There are three or four mainstream Java IDEs which all work very well. The industry standard for C++, however, is Visual Studio, locked to a specific platform, is large and sluggish, and has all the problems mentioned above and then some. Eclipse has a C++ plugin, sure, but it’s still not great. And heaven help you if you want to use code in VC++ that was created for GCC, or vice-versa.

Basically, C++ can be infuriating to work with, even more so after you use something like Java and then have to go back again. Applications are just becoming so complex now. I feel that there comes a point where if you’re heavily abstracting your code to avoid having runtime and development issues, you might as well try a language which does some of that for you. The performance in the long term is probably not going to be that different, but your development experience might be much more enjoyable, and the likelihood of bugs goes down dramatically.

I still want to properly try C# sometime. I believe that it can possibly be obfuscated better than Java, which due to its nature makes it much easier to decompile and reverse-engineer than C/C++, which isn’t good if you’re making commercial software. But there’s still a lot of things about Java’s nature that I enjoy which even C# doesn’t do, so it’ll really have to blow me away to convince me to switch. That, and the development IDEs are going to have to be really darn good. Java has spoiled me, and I don’t care to admit it.

John Wayne says:

It looks like you’re looking for something like it has the defer from Go, without the GC. And it keeps a lot from C. Not finished yet. As for myself, I’ll stick with Rust. Ark at least seems to have a sane module as oposed to C/C++.

 Write a comment


Do you like our videos?
Do you want to see more like that?

Please click below to support us on Facebook!