C++ is, hands down, one of the most misunderstood languages in software developer pop culture today. People often compare it to C because it is a "low-level" language. Consequently, it has received a reputation of being an esoteric language that only the performance paranoid care about. This is far from true. I have been programming in C++ as my primary language for a while now and the developer experience is actually really good -- much better than I had imagined it would be.
In this article, I want to debunk some common myths about C++ that I heard before I started using it. Then, I want to talk about the actual superpowers that C++ provides you that most other languages do not.
Myth 1: memory this, memory that
We all know that C is infamous for manual memory management e.g. with the malloc
and free
. They are hard to work with, lead to many error conditions that need to manually be checked for, and is overall a nightmare. When people hear that C++ also has great performance, people assume that it is by dabbling into all the specifics of memory allocation much like in C so they conclude that it would also be a nightmare. This is categorically false.
For a while now, C++ has had smart pointers. Using these, you can get the same behavior as you get with objects in other languages like Java and Python. In particular, the std::shared_ptr
works by wrapping a regular object in a copy-able and movable object with a reference counting mechanism. Thus, when no code is referencing a shared_ptr
, it is safely destructed and freed like in most languages. The simplest way to construct a shared pointer is as follows:
std::shared_ptr cat(new Pet("cat"));
// or
std::shared_ptr cat = std::make_shared<Pet>("cat");
While this is the common pattern in most other languages, C++ allows you to have further control on how an object is accessed e.g. using a unique_ptr
, but more on that later.
Overall, with smart pointers, managing memory in C++ is no harder than any other languages. It is, however, intentional in that you need to clarify that this is your expected behavior because you can still create and pass around regular pointers the good (ugly?) old way.
Typically, with good use of these, you are also very unlikely to run into segmentation faults which were oh-so-common in C.
Myth 2: it is old and outdated
C++ is very actively maintained with new features that continue to be rolled out at a regular basis. I think one of the most common "new" features in many languages that people have grown to admire is lambdas. Surely, C++ doesn't have lambdas right? Wrong. A C++ lambda function can be defined as:
auto square = [=](int x) { return x * x; };
For context, Java got lambdas in 2014 with the release of Java 8. C++ has had lambdas since C++11 (2011). Yep.
And there continue to be major updates e.g. C++20 most recently, that introduce even more features to make C++ easier to work with. For example, variable-length arguments have been in C++ for a while with variadic templates. Generics work great in C++ as well, although differently from what you may be used to in Java. These features continue to improve the way we develop software.
Myth 3: it is easy to get wrong
On the contrary, while learning some of its quirks may take a while, C++ makes it very hard for your code to do undesired things. For example, many object-oriented languages do not have support for "pure" functions i.e. functions that are guaranteed to be immutable. In C++, you can actually mark methods of a class as const
if they don't modify the class' state. These methods can then also be called on constant instances of the class. Here's an example:
class Greeting {
public:
Greeting(std::string greeting) : greeting_(greeting) {}
std::string get_greeting() const {
return greeting_;
}
std::string set_greeting(std::string new_) {
greeting_ = new_;
}
private:
std::string greeting_;
};
Now, you can initialize this class as a constant and still call the getter. If you try to mutate the state of the class, the compiler will complain!
const Greeting g("hello");
g.get_greeting(); // returns "hello"
g.set_greeting("hi"); // does not compile
To be accurate, these functions are not fully pure in that if you don't type some of your variables correctly, it is possible to mutate the resources. For example, if you have a const
pointer to a non-const
object, you may not modify the pointer but can modify the object pointed to by the pointer. However, these problems can typically be avoided by typing the pointer correctly (i.e. making it a const
pointer to a const
object).
It may seem like I am self-contradicting here by mentioning such an edge case in a common use case. However, I don't think it really contradicts what my larger claim here is: C++ makes it hard to go wrong assuming you know what you want by giving you the tools to express exactly that in code. While programming languages like Python might abstract it all away from you, they come at a much higher cost. Imagine going into an ice cream shop and only having chocolate served to you because that's what most people generally want -- that's Python. Depending on how you look at it, sure in some sense it is harder to go wrong with chocolate, in general it is not upto the shop but the user to know what they need.
Good const
-ness is a big plus but there's several other things that C++ allow you to do that prevent production bugs from occurring in larger projects. It allows you to configure move/copy/delete semantics for the classes you design if you need. It allows you to pass things by value and advanced features like multiple inheritance. All these things make C++ less restrictive.
Myth 4: it is verbose
Okay, this is not completely inaccurate. Coming from Python, where folks are so tired of typing numpy
that they just collectively all decided to import it as np
, typing more than 2 letters does feel verbose. But modern C++ is a lot less verbose than it used to be! For example, type inference like Go is available in C++ with the introduction of the auto
keyword.
auto x = 1;
x = 2; // works
x = "abc"; // compilation error
You can also use auto
in return types:
auto func(int x) { return x * x; }
You can also use it in for loops to loop over maps for example:
for (auto& [key, value]: hashmap) {...}
auto
does not mean that the types are dynamic -- they are still inferred at compile time and once assigned, they cannot be changed. This is probably for the best. In practice for large codebases, it arguably also helps readability to specifically type out the full type instead of using auto
. However, the feature is there if you need it.
You can also specify type and/or namespace aliases like in Python. For example, you can do something like:
using tf = tensorflow;
// Now you can use tf::Example instead of tensorflow::Example.
C++ templates (similar to Java Generics, but pretty different at the same time) can also help significantly cut down duplicate code and may be an elegant solution for many use cases.
Overall, C++ is definitely more verbose than many new programming languages like Kotlin and Python. However, it is not a lot more verbose than C# or Java or even JavaScript to some extent, and the verbosity of those languages has not affected their popularity too much.
Myth 5: hard to do common things
Again, this is not completely inaccurate. Common operations like joining strings by a delimiter are more complicated than they need to be. However, this is a problem solved rather easily with open source libraries like Google's Abseil with thousands of utility functions that make it very easy to work with. Apart from string utilities, Abseil also contains special implementations of hashmaps, concurrency helpers, and debugging tools. Other libraries like Boost make it easy to work with BLAS routines (e.g. dot products, matrix multiplications, etc.) and are very performant.
Using libraries itself can be a challenging task in C++ with having to maintain CMake
files, although in many ways those are not much different from the gradle
or package.json
files in other languages. However, again Google's open source build tool Bazel makes it extremely easy to work with even with cross-language builds. It takes some getting used to, but provides really quick builds and in general has a very good developer experience.
Superpowers
So after busting all those common myths about C++, here are some things in C++ that a lot of other languages don't allow you to do:
Customize semantics of your classes
Suppose you have a class that contains some large data. You would prefer it not be copied and instead be passed by reference always. You can enforce this as a designer of the interface. Moreover, you can configure exactly how you would like it to be copied if at all it is required.
What about moving objects -- instead of copying all data from the previous block of memory to a new block and then deleting the old block of memory, maybe you can optimize it by just switching the pointer locations.
What about destroying objects -- when a object goes out of scope, maybe you automatically want to release some resources (e.g. think mutexes that are automatically released at the end of the function). This works much like the defer
functionality in Go.
As a designer of an interface, you can customize every small aspect of how users will use your class. In most cases, this is not necessary but when it is, C++ allows you to fully express your requirements. That is very powerful and can save your company hours of time on large projects.
Optimize memory access
I briefly mentioned smart pointers above. Apart from shared_ptr
, you can also have a unique_ptr
that ensures that only one object can own a resource. Having one owner for data makes it easy to organize and reason about large projects. In fact, while shared_ptr
most closely mimics Java and other OOP languages, you're generally better off using a unique_ptr
. This also adds to the safety of the language.
You can also specify compile-time constants to enable the compiler to do more work during the build so that the binary runs faster overall.
Strong types
In general, I have found that working with typed objects is SO much easier to debug than other languages. For example, after hours of debugging a JavaScript project, I found that the error arose because I was passing in 1 argument to a 2 argument function. JavaScript threw no errors and just produced undesired outputs. I would much rather have something fail to compile than fail during runtime.
However, there are many typed languages out there so it may seem overkill to use this as a super power. But C++ does more. First of all, C++ lets you pass anything by reference, by pointer or by value. That means you can pass in a reference to an integer and have a function mutate it instead of using the return value (might be handy in some cases). It also means that you can perform memory-level operations using a pointer on anything if need be. Usually, though, you would like to pass things as a constant reference (e.g. const A&
) which does not lead to a copy and keeps your object safe from being mutated unintentionally. Those are strong guarantees to have and that makes your code just so much easier to reason about. In typescript, for example, you cannot reassign a const
object but you can mutate it. Why even -- just uggh.
Caveats
So C++ is great and all, but there are obvious limitations to what I would use it for. You can write microservices (e.g. in gRPC) rather easily but I would likely not use C++ for the actual web server (I would likely use TypeScript for that). Despite its speed, I would likely not use C++ for data analysis (I would likely use pandas
for that). There are some things that C++ is great for and there are other things that it's just not suitable for. Ultimately, you still have to choose the right tool for whatever job you're trying to accomplish. Having said that, hopefully this article made C++ a bit more attractive in your eyes than you're used to seeing it as.
Top comments (26)
Counterpoint: there are way better languages.
C++ is unsafe. Rust is better while still giving low level control and performance. Not to mention VM languages like Java...
C++ isn't faster than Java, Go, Rust, C etc.
C++ libraries aren't even remotely close to the stuff you get with Java, Python etc. Even basic stuff is pretty hard to do. Hell, I had a job to fix an XSLT processor in C++, it would have been easier to just rewrite that whole thing in Java in a couple of hours.
C++ tooling isn't nearly at the level of Java. Neither in terms of debuggers or in terms of static analysis, refactoring etc. The closest thing is visual studio which is a proprietary windows app. Even jetrains tools lack when it comes to C++, it's just too hard even for the tools.
C++ still isn't portable in 2021. Yes you can code defensively but it's still bad and you end up in Macro hell with cmake configuration from hell.
C++ takes ages to compile because of features such as templates... When it fails the compiler output is downright unreadable.
C++ has a lot of hidden features/behaviors that are often compiler specific. It has nuances that are easily triggered and fail in odd ways.
C is much simpler, doesn't suffer from template bloat and compiles faster. It's more portable (albeit also with its own problems).
I liked C++ a lot in my youth. As I grew older and had to maintain code on multiple projects the pain of C++ became very apparent and I learned to hate it deeply. When I last needed to write a JVM I used pure C and it was remarkably easy. C++ is just unpleasant to work with.
Ultimately you're entitled to your opinion but there are some things I disagree with.
Like I mentioned in my article, tools like Bazel make builds significantly fast. I personally don't prefer using CMake. There are static analysis tools like Kythe that also work beautifully with C++.
Like it or not, virtualization has a performance cost and a simple Google search would confirm that this makes C++ faster than Java at least. For many use cases, the advantages may outweigh the costs and that's fair. I personally love the Erlang VM and all the guarantees that it provides and I'd much rather use Elixir/Phoenix than C++/OpenMP to build real time distributed apps.
If you like the simplicity of C, there's nothing wrong with that. It just comes with its own memory management nightmares when you need to work with the heap. C++ simplifies that a lot without losing performance advantages of C. There are other things like function pointers which are wonky in C but much better in C++. Also, for larger projects, OOP makes it much easier to design systems IMO, but that is a personal preference.
Depending on how you define portability, C++ actually can run on any system and if you don't use very low level features (which you can't use in Java/Python anyway without C/C++ shared libs), it really does compile and run seamlessly.
CLion and Visual Studio suffice all my general needs when writing C++, but I have friends who use VSCode with C++ extensions as well and that works well for them.
C++ is only unsafe and unpredictable if, like I said, you don't know what you're doing. Languages like Java take thinking away from you by putting all objects on the heap and only maintaining pointers. If you know what you're doing, you might not want that in some cases. This causes issues with Garbage Collection being extremely slow.
Again, in the end it comes down to preference. Whether or not you find a language beautiful and elegant is subjective and while I've tried my best to convince you with this article that it's not as unpleasant as most people remember it to be, I don't mean to belittle any other languages. They're all awesome and I use several of them all the time.
Fast is subjective but inherently C++ compilation is MUCH slower than most languages. There's just a lot more to evaluate and unpack. This is an inherent limitation. It might be OK for smaller projects but even at 100k LoC this is very noticeable.
I pretty much disagree with most of your points but this one bothers me the most:
Two things bother me here:
Thinking we're smart - that's a dangerous path to walk. All you need is one lapse of judgement, one botched code review, one weak link and boom. I worked with a lot of very smart people who wrote dumb code a few times. The assumption that we're smart or that we "know what we are doing" is a flawed assumption. You're also making that assumption of every team member, every dependency and library you use and every update you get...
GC is slow - This is a common falsehood that derives from bad implementations and configurations.
GC allows super fast allocators in Java. In fact it beats some of the fastest C allocators. The cool thing about GC is that de-allocation can happen asynchronously on a separate thread during CPU idle time. That's very efficient...
The points where this becomes a problem are:
Newer GCs deal well with both of those cases through multiple strategies that include concurrency, generational division etc. The thing is that memory management becomes a "deployment decision" and not something the programmer should decide during development. You can profile the performance of your application in runtime and fine tune the GC/memory to produce predictable high throughput results.
I respect the fact that you have had different experiences than mine, so I'm not going to argue with your assumptions. I've worked on C++ and Java apps at Google scale and in my experience, C++ builds have been no slower than Java builds (with the right tooling, like I mentioned before). But again, there are a lot of infrastructural factors that can come into play that can influence your experience.
Things like fine-tuning GC just defers the problem instead of solving it. Furthermore, C++ being a compiled language, it does in fact run faster than bytecode in production. Again, it's a tradeoff that you may be willing to make but it's a bit extreme to impugn that the tradeoff doesn't exist.
I'm not assuming there isn't going to be a lapse in judgement at any point. In fact, if you want to play it safe, you can just use shared pointers all the time and avoid all the memory allocation risks that you'd otherwise face. In that regard, C++ is no more unsafe than other languages. As a class designer, however, I find it a lot more expressive to be able to further impose constraints on how other programmers use the interfaces I provide to make it harder to use it incorrectly (oreilly.com/library/view/97-things...).
All of these are design choices and tradeoffs, and they are intrinsically subjective in nature. As a result, I am not going to defend C++ any further on this thread. It's a widely popular language with or without your liking towards it.
Thanks for the discussion though, I did learn some new things and it's always engaging to hear other perspectives!
C++ was faster when Google search was developed. It's not as simple today. Performance is a more nuanced debate at this level and benchmarks can mislead both ways. C++ is not faster and neither is Java. There are benchmarks that can go either way.
A JIT inlines virtual methods at runtime, that's something a C++ compiler can't physically do. This is one of those super optimizations that can make a frequently used code path scream since it serves as a basis for further, even deeper optimizations. A well tuned GC can place the peek where you have idle time. C++ will pay a higher price usually on the same thread where things physically happen. To be fair a GC typically needs more RAM to play around with, especially with a JIT. It can tradeoff of more RAM vs. higher performance vs. fewer pauses but would still take more RAM overall.
Using shared pointers for everything is 2x slower at least, which is exactly my point. The C++
new
operator is already slower than Javas new. So you pay a performance penalty for careful coding and lose the advantage C++ is supposed to give you.I wanted to slip in a real world example of a very performant GC. GHC, the most widely used Haskell compiler, uses GC in the compiled runtimes and it's designed around the fact that Haskell works with immutable data.
In result Haskell applications easily match other application performance written in lower level language, at times even exceeding their performance, thanks to optimizations that GHC can apply due to highly expressive Haskell typesystem.
C is nice and all but we should stop using C and start looking into a safer lang. The unsafe properties of C is not gonna cut it in the next years where safe code is going to be important. Code is going to run even more on cars and other mission critical platforms. Maybe Rust. dont know.
I very much agree. When I built ParparVM I picked C as the underlying language. Rust wasn't a realistic option back then. Had I done that today I would totally have picked it.
I was going to rebut your counterpoints since I'm a C++ fanboy, but I think they're all true. (I've been programming in C++ for 33 years now. My current project is an extremely large, extremely old C++ project)
Some of the counterpoints are a bit a "matter of degree", most of others are "yep, no doubt about it".
C++ tooling will never be as good as Java or C# tooling. Lack of reflection, lack of introspection, lack of AST manipulation, and the preprocessor are all huge barriers to having powerful reliable and robust tooling. The refactoring tools for Java and C# are killer features in IDEs like Visual Studio with Resharper or CodeRush, or Eclipse, or the wonderful IDEs from the folks at JetBrains. That's the counterpoint that stings the most.
Mr Almond, you said that C++ is unsafe but you didn't give any clues. Then you said Rust is better (did you mean safer?) but you didn't mention in which sense. And you didn't give any clues again. Then you said C++ isn't faster, but you didn't mention any benchmarks. I stopped reading further because from what I read I conclude you are biased and opinionated against C++.
These are common terms and easily checked. I suggest reading this: en.wikipedia.org/wiki/Rust_(progra...
You can also do a slight bit of self research to learn about these things on your own e.g. this article is a bit out of date (and has problematic choices) but shows off some of the complexities of decreeing C++ as faster: en.wikipedia.org/wiki/Java_perform...
I've been a C++ developer since the early 90s. Hell yes, I'm biased against C++. I've also built JVMs (mostly in C but also in C++) so I'm pretty familiar with the performance nuances and benchmarks. Feel free to disregard my experience and go back to your bubble.
I love Delphi, but that´s not the point. The times that people used only Windows or Linux are over. With C++ you are bound to one or the other platform.
Though I did not like Javascript too much, I have switched over from Delphi/C++ to Javascript for some reasons:
I personally think that some concepts of HTML and CSS are really bad and prevent a good programming style (See my post: What´s wrong with webdesign), but this is nothing you cannot overcome. You can use for example DML for web programming without html, and there are possibly other solutions to deal with that topic.
I perfectly understand people who love "their favorite programming language". But finally, we should not forget, that a programming language is a tool only. There are different tasks, so we need different tools. Visual Basic is the pure horror for me, but it is ok for some scripting in Excel.
So, many thanks for the writeup, it´s good to know about the concepts and powers.
Don't get me wrong, JavaScript works pretty well for web dev use cases. But I disagree regarding your point about being bound to one or the other OS with C++. With WebAssembly, C++ can run on the browsers. C++ can also run on OS X, Androids and even embedded devices.
That aside, like I said, I would likely not use C++ for building web servers. It serves a specific purpose in your toolkit and it's good to have. If the only thing stopping you from choosing it is because you're scared it's esoteric, the purpose of this article was to convince you it's not.
Well, we had that precise question: We had some well designed applications, some with more than 60.000 lines of code. Our question was: can we bring this apps to the web somehow? I suppose, WebAssembly will not help us here, as they provide a completely new ecosystem. Finally it would mean to rewrite most parts of the code.
We will see how WebAssembly develops. Currently is seems to be a young project that has not too much impact. Maybe if they get direct access to the DOM this could change. I would really appreciate if there was a new binary layer able to run languages other than JAVA. But currently we cannot ignore that this is not the common state.
Yep that's a fair point. The sad truth is that the dominance of JS on the web is hard to replace given how much tooling we now have built around it.
Initially I did not like JS at all. There are still somethings I hate the designers for (most of all the overwhelming use of "this" in class definitions). But I was amazed that we had less trouble than expexted in our projects. You can have real trouble with the sloppy type conversions. But we had this kind of tricky errors too in languages with static typing.
You will need some more checks and a bit different style with JS, but the loose typing can also be very elegant. Overall it is not as bad as expected. Definively better than Visual Basic. It is more like an ugly, but very handy friend.
Initially I thought, TS is a must-have. After I got a bit used to JS I'm not that sure.
Back when I learned coding I learned C/C++ as my first languages and I loved it! Over a few years I occasionally had to use other languages like Python/JS for larger projects but I was kind of disgusted by the fact that even most Senior Devs I met - especially if they only used JS - didn't know how the languages worked internally.
C++ ist awesome to learn because it requires you to have a rather high level of technical knowledge/understanding. I used to believe every dev had that level but that's simply not true.
Anyway, a few years later I found Rust.
Nowadays I strongly believe that anyone who prefers C++ over Rust simply doesn't know Rust.
I may be wrong, but libraries and frameworks like OpenCV, Torch/Tensorflow, Unreal Engine only really have unofficial Rust support. The purpose of this article wasn't to discuss X is better than Y, but rather to discuss why C++ is in itself a pretty cool language and not as bad as people deem it to be. And while not everyone might understand the nuances of C++, it is a great language to really learn how things work and gain that technical knowledge and understanding.
I used C++ around 30 years ago for 3-4 years while I was working on my startup project. At that time I was in love with C++. For me the most dangerous and annoying problem of C++ is having features like multiple inheritance that let developers create a very complicated non-managable code. Even though these features are superpowers of C++ but still are not necessary. Also in my opinion C++ syntax is ugly, old and complicated. In my opinion, a programming language should have the following charactristics:
1- Push developers to use best practices more and more
2- Have a tendency to simple readable code (anyway these languages are created because our brain cannot simply read the assembly language or binary codes)
3- Generate fast, reliable, predictable and safe code.
To my understanding, programming languages are now having a much more sensitive role than what they had two or three decades before. They are controling our homes, cars, sensitive medical devices and even our homeland security. Neglecting of the above features is far beyond the purpose of having a good software creation tool. That is why I think we should stop using C++ in our embedded vital devices, and instead use Rust or other alternatives. C++ still can serve in many areas such as game industry.
I feel like what points (1) and (2) come down to is how opinionated a language is. Python and Go, for example, really care for "one right way to do something" which automatically produces code that follows best practices and are readable. C++ isn't really designed to be opinionated, and that has its advantages and disadvantages, but large codebases typically define their own guides and enforce them automatically to achieve that. It may not be the best solution for all teams and developers though, I agree.
Great article!
Makes me wanna try c++ again
I also think C++ is the most wonderful programming language in the world.
I love C++. I have been doing C++ since the 90's. Thing is, there wasn't much of an option back then for Windows developers. There are things about C++ which is a big pain. char*, wchar_t*, BSTR, CString, std::string, _T, L, I mean sometimes it really feels like a joke.
I believe you HAVE to be really good at understanding whats happening under the hood to avoid making silly mistakes in C++ and I do like working close to the system so I have always enjoyed this. However, when there is a deadline, this type of potential hazard isn't something which is a lot of fun.
Today, software has to be developed super fast and ship yesterday. C++ isn't really the language for this. Most application have now become web based. A lot of stuff involves dealing with dynamic data at runtime. Without strong reflection support like .NET or Java, life becomes pretty complicated.
I have left C++ to the system folks and I am not one of them. I work mainly on business applications, Apache Flink, Java, .NET, SQL and others. The amount of productivity required by my teams will not be supported by the use of C++.
I still follow the C++ community. I recently got a book on C++ 20 and I intend to read it cover to cover. Yes, I do love C++ but I will not introduce it in my projects.
Coming to Java, having coded .NET since Beta-1, Java has always been a bit of a joke. Its 2021 and the language features of Java look really primitive. If one says C++ is redundant, Java should be more so. Its a terrible language. int vs Integer. No real function pointers. but propping up modern features using age old constructs like interfaces? Its hilarious. When I see the advertisement "Java runs on 4 billion devices" I often wonder if the C-19 virus thinks the same, "Infected 4 billions people". People need to stop using this terrible language. The JVM is great, but not Java, no there are much better alternatives.
Java Script. This is something which should never have been invented. It was kind of OK when all it did was check if textboxes in a web form were left empty, but nothing more than that. By the time I finish writing this comment, I am pretty at least 2 new JavaScript frameworks would have been written. Using frameworks like Angular, Vue, React is a complete waste of time and energy. None of these frameworks last more than 2-5 year. Strangely code written using C++ MFC, Java, even Visual Basic 6 is still running fine in majors banks and other companies.
C# in my opinion is the best language there is. The tooling is pretty good, Visual Studio is a great IDE. I hope .NET core really breaks some ground specially with the good folks at Apache foundation. I hope there is a time when .NET is the language used to create indexing services, distributed computing frameworks, frameworks dealing with big data and more.
Cheers.
Should we all just use go instead? Just wish it was oop!
I learn c++ on university
I like c+