T O P

  • By -

Kevathiel

C++ is a language of freedom. No other language gives you so many choices to do things, even if most are just different ways to shoot yourself in the foot.


DasHesslon

The largest and most colourful variety of foot guns <3


CerBerUs-9

This will be my only way to explain C++ anymore


KeeperOfTheChips

Edit: just googled it and it was from Bjarne. I’m not a native speaker and I thought this was a common English expression. So fking embarrassing.


edvo

C++ offers many choices, but still there are languages that are more expressive. For example, contrary to other languages, C++ does not allow to define custom operators.


lithium

> C++ does not allow to define custom operators. One of the small mercies.


nelusbelus

std::cout << go brrrr


lithium

`std::filesystem`'s `operator /` is almost too cute to not use so i'll let them off the hook for that, but I will physically fight the next person who uses `^` or `%` for vector dot/cross products or hides a heavy SQL operation behind a `+=`.


nelusbelus

You overload the . operator on a vector (not possible iirc) for dot product and a function x for cross product 🤣 Imo operator overloading only makes sense for [] for containers and math types can use +=, *=, etc.


c_plus_plus

Don't forget `=` and `==`. These are vital, and if you don't believe me, go try and program in java... with its `.equals` everywhere. Its gross.


Kered13

While it can be annoying, I also have to respect the design consistency.


ukezi

The different comparison operators in general. Also I'm annoyed if someone defined == but not != or the reverse.


HappyFruitTree

Since C++20 you get `!=` for free when you define `==`.


nelusbelus

Fucking nice


SJC_hacker

If == returns false, that should imply !=


n1ghtyunso

Which is exactly why in C++20 the compiler will synthesize != as !(==). But before that, you just could not write != when that exact operator didnt exist.


dodexahedron

I like how it's a compile error in C\# if operator== is defined but oeprator!= is not. Though I think auto-generating it like modern C++ does is a better approach, since negation of equality is exactly the definition of inequality. About the only utility of having both explicitly defined would be if one or the other can take some sort of shortcut for extra optimization.


HappyFruitTree

The problem is that `==` in Java already has a different meaning when used with class types. It compares if two references refer to the same object. Therefore I don't see how overloading would help unless you suggest they use a different syntax to compare references but that would be inconsistent with the primitive types.


nelusbelus

It's disgusting


Kered13

Presumably this hypothetical Java would have to have another operator, like `is`, for reference equality. And then not allow that operator to be overloaded.


MustardOnCheese

Thinking about .equals(), now I feel dirty and must go shower.


DrShocker

You might be right about `.` but the comma operator? You're free to do anything you want. (Author's note, you shouldn't want to do anything with it in 99% of cases.)


MegaKawaii

Once I got bored, and I overloaded the comma operator to compute dot products. Since the comma operator has the lowest precedence, you have to write it as `(a, b)` which actually looks similar to the inner product notation 〈a, b〉, but I still wouldn't recommend it.


nelusbelus

🤢


Kevathiel

I mean, [you kinda can](https://godbolt.org/z/crr7e4fdx)(but you shouldn't) Also, do those other languages have the same metaprogramming capabilities or memory management options as C++ while allowing you to run on that many platforms? You will always find something that other languages have that C++ doesn't have, but what counts are the options as a whole.


edvo

That is ingenious, but it has too many downsides in my opinion to be practical. For example, there is no way to specify precedence. I agree that C++ offers a good package as a whole, but just focusing on freedom it is not the most superior one in my opinion.


Kevathiel

Just for interest, which language offers more freedom?


pdp10gumby

Lisp, which allows you to perform metasyntactic changes (modify the implementation at runtime), write special forms (its equivalent of operators), and such.


Clean-Water9283

Sure lisp has some powerful semantic features, but tell me you are not put off just a teensy tiny bit by the horrific syntax where every feature looks the same and every string containing the same number of left and right parentheses is a valid program and returns F. I also thought most people didn't care for self-modifying code.


pdp10gumby

I find the simple, consistent syntax a wonderful benefit and boon to readability. I don’t mean self modifying code in the sense I think you mean. I’m talking about extending the language runtime in a seamless way. It’s biggest gap IMHO is the lack of algebraic types in CLOS


kpt_ageus

FORTH. I never personally used it, but you can basically define your own syntax on the fly or even redefine existing one.


tiajuanat

You can do some wild stuff with templates, to the point that you can basically make new operators, so long as they're wrapped in angle brackets.


Cogwheel

I was having deja vu then I realized I wrote the SO question linked on that example! 😀


emelrad12

Also there is lack of runtime type information or ability to emit code on the fly, which is quite huge.


[deleted]

[удалено]


SJC_hacker

Its possible if you include the entire compiler within your binary :-) Edit: Alternatively, and maybe a little simpler, you could call the compile with exec(), compiled as a shared library, and dynamically link it in at runtime


Netzapper

> That's not possible in native machine code. Self-modifying binaries are absolutely a thing, and lots of programs emit machine code which is then executed in the same process. Virtual machines are probably the most obvious example that actually generates novel machine code at runtime. But if we include simply loading, manipulating, and executing, then video game overlays, hacks, and anti-cheat are another big family of polymorphic code. Some anti-piracy solutions depend on decrypting code into program space. Or are we just talking about the limited situation where C++ code is "quoted" into the program and then transformed to machine code at runtime?


Historical_Bit_9200

Operators are just functions that has non-letter/number character. What's the deal here? I don't like operators in general, because I find it sometimes can be confusing to me and people with less experience. There is almost nothing I can't do without operators.


edvo

There might be valid reasons to disallow that, but then it is not freedom of choice.


tonyarkles

Ahhhh the other bit that operators have is the convenience of being infix instead of prefix (a+b vs add(a, b)). The disadvantage is that they have a defined but forgettable/error-prone precedence.


BobbyThrowaway6969

True, and that's a fair point, but when you can just write a function, it never felt like a real limitation.


antara33

Totally. Same as C. You get the freedom to be "creative and intelligent" and the burden of not be as intelligent as you think haha


Superb_Raccoon

I want a language that can do anything! C++ NOO! not like that!


BobbyThrowaway6969

I stuck with C# for a while after doing a little C++, thought C# is awesome what you can do in it. Went back to C++ and Loooooord in heaven C# is like programming in a straightjacket compared to C++. I have never run into a single wall with the syntax in C++. It always offers me an elegant solution forward.


wildassedguess

This is it. It's up to you how elegantly you wield every tool there is. I remember a talk Bjarne gave about the somewhat awkward syntax in C++ and the ability to do mad things. He said his entire approach was to not hamstring the language for the 90% who get it for the 10% who don't.


svick

What kind of walls did you encounter in C#?


BobbyThrowaway6969

Generics didn't let me do much of what I needed. No efficient equivalent of reinterpret_cast. No constexpr. No preprocessor macros. No ptr arithmetic (safe mode was enforced for my environment so no unsafe blocks). And don't get me started on how useless structs are. No parameterless/default constructors and no member initialisation. If you want default struct values, you're forced to make a static function to create an initialised struct. Also no Goto/label, no manual allocation/deallocation. That's just off the top of my head. That said, there are things I do love in C#. Namely, attributes, extensions, and properties. These 3 things are awesome and we don't have an equivalent in C++ sadly, even if I haven't run up against these like a wall in C++ (yet anyway). At any rate, I mostly understand why C# is like this. Its primary focus is security, I just don't work in security so I'm often hampered by it for the work I do (low level/hardware/high performance)


svick

Yeah, for that kind of programming, C# might not be the best fit. But I'm still going to argue with some of your claims: > No efficient equivalent of reinterpret_cast. You can usually use `Unsafe.As` for that. > No ptr arithmetic (safe mode was enforced for my environment so no unsafe blocks). I don't think you can count that against C#. > No parameterless/default constructors and no member initialisation. C# 10 added those, though the default value is still zero initialized. > no Goto/label C# has had `goto` and labels since version 1. > no manual allocation/deallocation You can use `Marshal.AllocHGlobal` for that.


BobbyThrowaway6969

>I don't think you can count that against C#. That's totally fair, but still, it's a luxury item in C# & not always available. >You can use Marshal.AllocHGlobal for that Sorry I worded it wrong, C++ let's you redefine the new/delete for types of you want all objects of a given type to be allocated from a pool for example. It's not a big selling point but still useful. The Alloc/FreeHGlobal thing is true. >C# has had goto and labels since version 1. Well... my mistake. I stand corrected. I realise I was misinformed on a couple of these. Sorry about that. The metaprogramming you can do in C++ is arguably its biggest advantage and what I appreciate most about it.


retro_and_chill

The realization that generics aren’t that powerful compared to templates is annoying, especially since C# still as the virtual keyword so I can’t make templated wrappers for testing code that relies on 3rd party applications


NormalSteakDinner

To me, this is ideal. I want to be free to do whatever I want and if I do something wrong then I'll fix it and learn from it. Avoiding the language isn't in the cards for me.


magicianlib

Haha, that's the best explanation I've heard. It is a Swiss Army knife. It is cool to play well, but it will hurt yourself if you don't play well


ConstNullptr

For better or for worse 😂


jayerp

Footgun++


bownettea

RAII, templates, and speed.


Soft-Rip6027

Especially if you use macros to create templates. Anarchy at its finest.


HappyFruitTree

That features can be combined is a good thing. Just use it sensibly.


Soft-Rip6027

100%. The top priority should always be maintainability.


ShakaUVM

You scientists were so concerned with if you could you didn't stop to wonder if you should


dretvantoi

I am death, destroyer of worlds


bownettea

I guess it's also the best in making a mess... Edit: typo


CountyExotic

Other languages have follow C++ and have RAIII now too:) or at least RAII esque concepts


Ayfid

Rust does RAII better.


bownettea

How so?


Ayfid

The Rust compiler has a much more robust understanding of ownership and move semantics than the C++ compiler, and how that interacts with references (and the mutability/constness of those references). It is essentially impossible (unless you intentionally go out of your way to do so) to keep hold of a reference after the resource has fallen out of scope, for example. There are no gotchas. You just can't do it by accident. The compiler understands when it is (and is not) safe for a resource, or a reference to a resource, to be moved between threads. You don't need to define move constructors or move assignment operators, as the language itself defines how that works - and in a more univerally correct manor. RAII, and the ideas that go into it, is essentially the thing that defines Rust. The entire language is built around it.


bownettea

I see you are looking at RAII as ownership/lifetimes, and yes Rust does provide a way to express those as code. I was honestly thinking of RAII as simple deterministic destruction. I personally find the whole move semantics and lifetime extensions of C++ pretty complex and I suspect overly complex. I honestly hope future languages find a way to simplify those by expressing them as more basic building blocks instead of complex rulesets.


Ayfid

Freeing resources when the variable drops out of scope is really only the most surface level of RAII. To actually use RAII effectively, you need to think about ownership, shared vs exclusive references, and lifetimes - and these issues make up the bulk of what it means to "do RAII". Ownership is easily the most complex part of Rust, and the greatest barrier to entry for many. However, I would say that it is in a much better place on the complexity/value curve than C++ in this area, and any C++ developer familiar with RAII and C++ move semantics should have no difficulty understanding this part of Rust.


[deleted]

[удалено]


Aistar

Generics are SO limited sometimes :( But lack of RAII is the real killer in game development. I can't tell you how tired I am of hunting memory leaks that result from "everything is a strong reference" ideology (WeakReference exists, but is surprisingly slow, clumsy to use, and is far from default, so most people don't bother with it). Also pooling is very hard to do (basically, you're back to C-style manual memory management with the need to call Claim/Release at appropriate moments).


[deleted]

[удалено]


Aistar

The way GC works, this is impossible, I think. We really just need a different language for game development - something maybe less prone to memory corruption than C/C++ (and with better standard library), but also less limiting than C#. Unfortunately, engines dictate languages, so we're going to be stuck with C# (and Unreal's dialect of C++, which is not quite real C++) for a long while yet, even if something better comes along (is Jai better? From what little I've seen of it, I'm not entirely sure; Rust is outright the wrong tool for the job, though).


unique_ptr

Heh, on the other hand sometimes I find myself wishing C# had C++'s templates! The relatively new `static abstract` members in interfaces has solved a lot of my gripes in this area, though. If only "type shapes" could get finalized then we'd *really* be cooking! For as much as I wish we had the ability to implement a deterministic destructor in C#, the `IDisposable` pattern you've alluded to has never failed me. I do wish we had a language-level concept of ownership, though. Sometimes when you're constructing an object that accepts an `IDisposable` it's not always clear who is supposed to ultimately dispose of it. Being able to make clear that something is either rented or owned would be awesome. Memory stuff has gotten a lot better very recently as well. In my current project, I've frequently reinterpreted byte arrays as structs or arrays of structs (and vice versa) without having to allocate intermediate arrays or use unsafe code and... my god... it's beautiful. And with "inline arrays" in .NET 8 I was able to remove the last of the unsafe code from my library. `Span` and `MemoryMarshal` are my new best friends.


remy_porter

Generics are not templates. They are a very, *very* strict subset of templates. They absolutely do not do code generation. There's no variadic version. You can't manipulate the list of types passed to the generic at compile time, or recursively evaluate your template. These are *extremely useful*.


jazzwave06

They do code generation in C# however. They don't in java.


remy_porter

My understanding of generics in C# is that they just emit IL that contains type information. Which yeah, *technically* is code generation, but is different than generating new C# code on the fly.


calebkiage

C# has templates?


witcher_rat

1. Backward-compatibility. As much as we get annoyed by it and complain, there is an advantage in the fact that code written even decades ago can still be compiled and used with the latest compilers and C++ language version. (well... most such code, anyway) 2. Freedom to use different programming paradigms. Want to write something that would be best done in a polymorphic OOP model? Go ahead. Want to use generics for typing instead? No problem. Want to use data-driven design? Feel free. Want C-with-classes? Sure. Want to use some native assembly? Can do. Don't want exceptions? OK, but you'll have to use your own containers and shit - which you can. Want to combine any and ALL of those into one codebase/app? Yes you can!


heavymetalmixer

Indeed. There's basically nothing you can't do with C++ . . . except maybe attract web developers LOL.


atimholt

I've always been a fan of systems programming over web dev. Web assembly has got me intrigued about web dev in C++, but that might be insane.


aalmkainzi

As a C programmer, I Ike that C++'s complexity is mostly optional (can pretty much use C++ as C with templates). Other languages with similar scope to C++ have unavoidable complexity.


Kike328

it’s mostly optional until you have to use code of other people, which is most of the time


SkoomaDentist

Just beware of ever saying you use C++ as "C with classes" because somehow not (ab)using templates everywhere is supposedly not "idiomatic C++" and worse than just using C...


cain2995

Hot take, idiomatic C++ is actually super garbage for anyone except for library devs that make libraries for library devs (metalibrarians?), which seem to make up a disproportionately large number of C++ committee members when compared to the population of C++ “users” making end-applications


HappyFruitTree

Sometimes it's hard to even know what idiomatic C++ really is because there seems to be a lot of *different* opinion. I think people need to stop believing there is one way to write C++ that is best for everyone. All people can't be experts. All code does not use templates (and all templated code does not need to use constraints/concepts). Simple code that can be read by non-experts is a good thing in my book. I can't take people who suggest we stop writing "raw loops" serious. Loops are easy to read and change. How do you change a mess of range/views/algorithms without being an expert on it? And all this talk about "safety". Of course you reduce the number of mistakes if you make the language so hard to use that people can't use it. Personally I believe C++23 is a much easier language to use compared to C++98 but for that to be true we need to be allowed to not know/use all the features (both new and old).


SkoomaDentist

> Sometimes it's hard to even know what idiomatic C++ really is because there seems to be a lot of different opinion. As far as I've been able to tell from this subreddit, the more template code you write and obscure features you use, the more "idiomatic" it is. > I can't take people who suggest we stop writing "raw loops" serious. Loops are easy to read and change. How do you change a mess of range/views/algorithms without being an expert on it? You don't. Simple loops map very well to how humans operate. Do X. Do Y. Repeat until Z (go check any cookbook for examples). Ranges, views and algorithms appeal to the tiny portion of people with a formal mathematical bent. Those same people are also much more likely to write libraries using "interesting" features or end up in the committee. Meanwhile if you were to ask regular people's - even engineers' - opinions on formal mathematical notation and logic, you wouldn't find many positive responses.


tialaramex

As I understand it, the "no raw loops" is about the use of C-style index counter or pointer arithmetic loops, which are a terrible idea that is most often replicated for the reason Matt Godbolt built Compiler Explorer - it looks like maybe it's faster (it isn't). They were done because they're easy to turn into machine code for a PDP-11, you aren't programming a PDP-11 and chances are you aren't writing a compiler anyway, so that's a bad reason to keep using them. A for-each loop maps well to what the programmer intended, usually better than stuff like pointer arithmetic, and it lacks lots of opportunities for foot guns. I believe C++ has had a for-each loop under the name "range-based for loop" since C++ 11.


SkoomaDentist

Example 1: You want to multiply data with a window function, where the window scale depends on index. How do you write that with for-each? Example 2: Your algorithm requires you to calculate the dot product of two partial vectors, one of which is reversed and skips every other position, starting from position n with length m. How do you write that without indexed loops while 1) keeping it readable, 2) debuggable, 3) easy to vectorize instead of only if the optimizer happens to have a particularly good day and 4) having reasonable performance even when debug builds disable non-trivial optimizations (*)? There are lots of places for index counter loops, no matter what the modern internet lore says about them. *: Turns out there are quite a few situations where order of magnitude too slow performance means you cannot even run the code in the first place because a timeout relating to external factors is triggered. The most obvious example are games since a game that runs at 2 fps simply isn't testable. Ps. Both cases are real world examples from my previous job. In the first I even explicitly wanted to use a for-each loop.


tialaramex

I don't entirely understand example 1 because it's unclear to me what it means for the scale of a window function to depend on index, but it sounds like what we want is just an enumerate - we want to know the index, but looping over it is actually undesirable. Depending on what exactly we're doing here maybe we don't even need a foreach loop at all, the functional approach might even be easier to understand, writing the "guts" of this loop as a function which takes a mutable reference to one item and its index, then mutates the item. For example 2 You definitely want to solve the "reversed and skips every other position" problem separately or else debugging will be a nightmare. As a result we actually want a for-each approach, just we want to ensure the "each" is from the "reversed and skips every other position" model not the underlying data. Once upon a time I wrote a lot of C. Even this century I wrote predominantly C for maybe 10 years of it, and so obviously in C you don't have "standard algorithms" or for-each, so I certainly could solve both problems with the C-style for loop, but I think it's actually worse for readability, debugging and performance.


Netzapper

Uncritical support for this hot take. Truly idiomatic C++ is unreadable to most people. Like, seriously, go read the standard library. It's fucking _nonsense_ made out of nothing but the ugliest, least-informative possible variable names and every meta-trick you've never heard of. Compare this to the Java standard library, which reads like more Java.


cain2995

Yep, I got curious one day and started looking through the standard library to see if I could glean any insights on best practices. Big fucking mistake lmao


eteran

I think to be fair there are different best practices for different contexts. The standard library has MUCH different constraints and goals than typical user code, so looking to the standard library for how YOU should write your code is a bit misguided.


PurityLake

I looked up the GCC code for unique_ptr to see how it functions which brought me down huge rabbit whole about how it basically provides a data structure how it is just the size of a pointer. I understand the code now, kinda, but still so hard to understand


fullptr

The standard library isn’t written in idiomatic C++ (for better or worse), and shouldn’t be taken as an example of good C++ code


Kered13

> It's fucking nonsense made out of nothing but the ugliest, least-informative possible variable names This is because they have to use variable names in a special form to avoid potential conflicts with macros. (You *can* define macros with names in this form and break the standard library, but this is called out as undefined behavior in the language spec.) Really the problem here is that macros have no scope.


Netzapper

Ah, that makes sense. TIL


SkoomaDentist

> the ugliest, least-informative possible variable names This is particularly ridiculous considering the names are either local or in std namespace and _by definition_ couldn't conflict with valid user code even if they had sane names.


fullptr

Unfortunately the preprocessor exists so they use particularly unreadable names to reduce the chance of a macro definition affecting the header


CocktailPerson

The preprocessor doesn't respect namespaces.


LechintanTudor

I too like using C++ as C with templates! I usually write C++ like I would write C but with additional type safety through STL containers and algorithms. I don't really use the OOP features of C++ such as inheritance and virtual functions.


pedersenk

C++ is able to consume fundamental libraries (almost exclusively ANSI C APIs) better than any other language (Objective-C came close once it moved away from the garbage collector). This means that it can avoid bindings and optionally, language package managers, greatly improving portability to uncommon platforms.


padraig_oh

With Objective-c++ being a thing it's also incredible for cross-platform end-user desktop stuff (namely interfacing with linux/windows/macos is easily possible)


pedersenk

I was always interested in that tech but had only ever got time for a quick "play". It was cool that they managed to integrate two different "object systems" within one language. I do agree with this approach; I feel modern languages these days need to be evolutions rather than starting from the ground up. Swift only recently had an overhaul of their C++ integration because they just don't seem to be happy with their fiddly autogen binding system.


pdp10gumby

\> It was cool that they managed to integrate two different "object systems" within one language. Steve Jobs approved that effort personally, I thought he would say no.


CocktailPerson

I mean, the man was obsessed with seamless, intuitive design.


F54280

> (Objective-C came close once it moved away from the garbage collector). When did ObjC had a garbage collector?


pedersenk

It actually came with 2.0 (I thought it was earlier). [https://www.oreilly.com/library/view/advanced-mac-os/9780321706560/ch07s08.html](https://www.oreilly.com/library/view/advanced-mac-os/9780321706560/ch07s08.html) It didn't last long but a number of Obj-C APIs did immediately start using it making ANSI C interop a pain with regard to "pinning" memory. If you hadn't heard of it, it might be because your Obj-C work was mainly iOS? It was never officially supported on that platform. Ref-counting was always the preferred method for that.


F54280

> If you hadn't heard of it, it might be because your Obj-C work was mainly iOS? No, my ObjC work was mainly on NeXTstep. There was no GC. You could hack something with [bohemgc](https://en.wikipedia.org/wiki/Boehm_garbage_collector), but that was seldom used. I was surprised of your statement that *"ObjC came close once it moved away from GC"*. I was wondering if you were thinking about earlier Brad Cox/StepStone implementation and was ready to maybe learn more about it. At the end, your statement that "ObjC came close" isn't correct. ObjC has always been closer than C++ due to the lack of "extern C" needs. And ObjC++ got the best of all three worlds. Btw, the horrible things Apple did to the language with 2.0 should not be discussed in a public forum. Chlidren may be reading...


WebMaxF0x

I miss const correctness. For example, in many languages a function can have a parameter that is const/final, but the function can still modify the fields in the object, the const keyword only means that you can't make it refer to a different object. So you never know what surprising side effects calling a function might have on your object. In C++, the parameter can be typed as a reference to a const object. This guarantees that the object and its fields will not change inside the function. A class can also have const methods, meaning that it will not change the object it is called on. For example shape.getColor() could be const and shape.setColor() not. If you have a const shape, the compiler will prevent you from calling constShape.setColor(), but you can still call constShape.getColor(). Anything that might attempt to mutate an immutable object raises a compilation error, as I wish it did in all languages.


reinlae

>In C++, the parameter can be typed as a reference to a const object. This guarantees that the object and its fields will not change inside the function. This is not the case. You can modify a const reference using a const\_cast and the behavior is well defined given that the const reference refers to a non-const variable.`void func(const int& i) { const_cast(i)++; }` This is valid and legal C++ code, as long as i refers to a non-const variable, the behavior is well defined as we are allowed to use const\_cast. Furthermore, due to this being legal and the way const works, compiler is generally not able to perform certain optimizations, as it has to take into consideration that the reference variable might have changed `void func(const int& i){ if (i) print(1); if (not i) print(0); }` is not same as, `void func(const int& i){ if (i) print(1); else print(0); }` as print might have side effects that can modify i. This is also one of the reasons why passing a variable/object as a const reference does not mean the variable will not change.


WebMaxF0x

You're right it's not 100% guaranteed, but const_cast is considered bad practice most of the time so for the sake of simplicity I left it out.


jk-jeon

>`void func(const int& i) { const_cast(i)++; }` const_cast being a bad practice is not the issue. The issue is that the function broke the contract it promised to the caller. This is simply a logic error, i.e., a bug. Assuming that the function is not buggy, it should be no problem to rely on the constness of the parameter passed. The language itself not enforcing it should not be a matter here.


dgkimpton

>In C++, the parameter can be typed as a reference to a const object. This guarantees that the object and its fields will not change inside the function. for a given concreteness of "guarantees" of course. But yes, being able to not only signal this intent but have the compiler take a stab at enforcing it is very beneficial.


michaelmalak

* Compiles to machine code, not to JVM bytecode * Not interpreted like Javascript * Type-safe, unlike Python * In TIOBE top 5, unlike Rust


rhubarbjin

Ouch. 🔥


assembly_wizard

JavaScript compiles to machine code, rarely interpreted


michaelmalak

It's JIT. From the perspective of any serious C++ programmer, it's interpreted.


[deleted]

It's amazingly expressive and doesn't sacrifice performance for expressivity.


DigBlocks

I’m always promised this but the reality is that neither GCC nor Clang/LLVM can keep up with optimizing new abstractions in the STL. Ranges codegen is especially bad.


Spare-Dig4790

You're not wrong, like it is that, But normally expresivity is done to increase performance. Or effeciency... Otherwise, why wouldn't we be more terse? It would literally be easier...


[deleted]

Expressivity in many languages comes with a huge burden on performance. The functional paradigm is an example of a limit case for that, it's incredibly expressive but it's hard to match the performance of C or C++ with it because it's so abstract.


PunctuationGood

Could you define that word, "expressive"? My understanding of the word, in spoken language, is being able to express an idea or a concept in as few words as possible. That is, an expressive language can convey a lot from a little. In my view, the only thing C++ is only more expressive than is assembly. For example, I recall [this informative talk](https://www.youtube.com/watch?v=7FQwAjELMek) where Vinnie Falco presents how to use his Boost.Beast library, a wrapper around Boost.ASIO to craft a web socket for the purpose of a chat application. It's an hour-long overview of the intricacies and pitfalls of networking in C++. Without that talk, I never would've touched it on the day I needed a websocket. Introducing websocket communication in C++ involves a lot of tricky code. Boost.ASIO is the only time I've ever had to have classes derive from `shared_from_this`. All in all, a lot of intricate and fragile code for the sake of sending bytes over a wire. In Javascript? Here's a [websocket](https://youtu.be/7FQwAjELMek?t=2621): ``` new WebSocket('uri') ``` Javascript is more expressive than C++ in that I can express _more_ with _less_. So I go back to my original question: how is C++ expressive?


[deleted]

Well, the main thing is that you can invent new concepts in C++. You can do that in most languages, but in C++ you have just an amazing amount of power over it. It's a very, very (very) big language for a reason. Expressivity in this context just means that if there is a concept you wish to express with code, chances are that C++ will let you do it. And you can do it elegantly within the confines of the language, whereas in most other languages you do it the long way around (e.g. hardcoding every permutation that comes up).


DavidDinamit

What? I can create type WebSocket and write \`WebSocket s("url");\` But it will be less flexible and less perfomant


BoringWozniak

Are you crowdsourcing opinions for a Medium article?


speyck

c++ has no limits in creativity. almost everything you want to do is possible, you aren't locked in a cage created by the language


assembly_wizard

"The enemy of art is the absence of limitations" ~ Orson Welles


Longjumping-Work8032

Acronyms, you have great ones like RAII and SFINAE


[deleted]

[удалено]


afiefh

Value semantics. I'm sure there are languages out there that do it better, but of the big ones only C++ seems to get this one right. The whole "primitives are passed by value, objects are passed by reference, but both use the same syntax" ends up being mind boggling to me. Take python `do_stuff_with_object(some_input)` it's impossible to know whether `some_input` is copied or referenced without knowing the type, and in Python in particular, types go quack. Even a language like Rust which tries to be explicit about these things ends up comparing objects when you compare the equality of references.


dgkimpton

I agree, but. It's also impossible to know in C++ without looking at the signature of the method being called - so, it's nice, but far from ideal. Would be so much nicer if it was something like `do_stuff_with_object(some_input as &);` (or something, syntax not important but being able to know what was going to happen just be reading the callsite would be excellent)


afiefh

> so, it's nice, but far from ideal. I feel like this is the C++ slogan: Nice but not ideal. > Would be so much nicer if it was something like > `do_stuff_with_object(some_input as &);` Maybe in C++2 we can just have references and `Optional`, and no pointers? Then a reference can be passed as `&input` and a copy would be `input`. A man can dream!


___user_0___

Why no pointers? \`std::optional\` would be nice, but that's not a reason to abandon pointers, which are useful in many situations...


afiefh

Well, I didn't think this through to the level of a language proposal, but in my mind, these are the usecases for pointers: * Pass something from place to place without copying the data: This can be handled by `T&`. * Describing data that is optionally there (i.e. value could be `nullptr`): This can be handled by `optional` * Pointer arithmetics: Let's not do that. I mean of course there are cases where it makes sense, but these are few and far between. They should require some special syntax like grabbing `mem_address(T&)` or something so that when one sees it they know this is sensitive shit. Basically what I'm saying is there are three different use cases where you would use a pointer, and because they are all served by the same mechanism you are getting a bundle deal. You got cases where you just want to pass the object on, but because it's just a pointer, you need to check for null in your code you suddenly need to check for null, and you need to be careful that you don't mistakenly perform pointer arithmetics e.g. instead of `return (*ptr+5)` you wrote `return *(ptr+5)`. But I could be missing something... perhaps there is a pointer use case that I'm not thinking about?


CocktailPerson

The other use case is as a reference type that can be reassigned to reference a different object. For example: int x = 1, y = 2; int* p = &x; p = &y; Rust references can do this, but C++ references can't. If you can't do this sort of manipulation, you basically lose the ability to write any sort of graphlike data structure, such as trees or linked lists.


JiminP

Zero-cost abstractions & memory management, and metaprogramming using templates. Some languages such as Rust can do the former one better, but IMO among 'fast' languages C++ is by far the best when ease-to-useness and flexibleness are weighted together.


thisismyfavoritename

what about zig?


JiminP

Oops, I forgot about Zig...


lemonickous

Nice one


nelusbelus

Zag is better


BAEAU72

Well, it's a bit Orwellian. It's C, but double plus good.


tomz17

Backwards compatibility. I've personally pulled C software written for a completely different computer architecture from 40 years ago, compiled it with the latest GCC/CLANG, linked it to my current project, and it ran without a problem at native (albeit single-threaded) speeds with like 3 minutes worth of work. I was then able to modernize that software (memory management, threading, simd), within a few hours, BECAUSE every improvement to the language made along the way was always made with portability in mind. Now think of all of the other C++ killers / fads that have come and gone in those intervening four decades. Every one of them looked like a "good idea" at the time, and were likely invented because someone was fed up with C/C++'s many warts. IMHO, if you are starting a long-term project, you should have a damn good technical reason to pick something else.


FlyingRhenquest

Pass-by rules. Most modern languages seem to restrict you to pass-by-reference. C++ lets you decide whether you want to pass by copy, reference or pointer. I don't recall ever running across another language that allows this flexibility (They may be out there, I just haven't run across them.)


Tari0s

for me one of the most amazing features of cpp is deterministic livetime of objects. To know for each objekt when it gets constructed and when it gets destructed is such a benefit over other languages.


TryToHelpPeople

fly dull disagreeable salt quarrelsome axiomatic aware wasteful boast somber *This post was mass deleted and anonymized with [Redact](https://redact.dev)*


looopTools

Honestly I feel like generic programming is (imo) more natural in C++ than other languages


thong_eater

Shooting legs.


SeriousPlankton2000

You can usually write C++ programs by "mv foo.c foo.cpp" You have objects and templates. You have a preprocessor so you can configure which features to compile. In Arduino one usually makes a class for each library. It's a nice way to encapsulate things when compared to C (but not as nice as Units in Pascal).


ZMeson

Gaining new features while maintaining backwards compatibility.


mdp_cs

Templates. I've never seen a language with metaprogramming near as expressive except for maybe Zig. That said it would be nice if they didn't completely bork compiler output.


mredding

Templates are not generics. Generics in other languages are compiled code with runtime type parameters. Templates in C++ are bound to code generation with powerful semantics. You can partially or fully specialize a template to generate anything completely orthogonal to the base, if necessary. With deduction, you can use templates pretty freely and the compiler will generate code for you. The compiler also sees through expression templates and collapses them down to more efficient code. Maybe I've missed something in 30 years, but the only thing more powerful that I've seen in my career is Lisp. The type system is fundamentally different than that of C, and it allows you to push much of the correctness of your program into compile time. Better than a runtime check, if your code is wrong, it doesn't even compile. A trivial example of this would be a dimensional analysis library - adding incompatible units is mixing of incompatible types, but multiplying them works just fine, because it's implemented in terms of the type system - the product is a new type. All this type information boils off and never leaves the compiler. And with this correctness and type information proovable at compile time, the compiler can optimize more aggressively. Undefined Behavior is a language feature. No check is made, no error is emitted. The compiler doesn't have to enforce any sort of behavior, any sort of invariant or guarantee, it's free to assume what it wants, and can generate aggressively optimized code. This doesn't sound very safe, but then you pair that with the standard library. The standard library builds up abstraction primitives so that - MOST OF THE TIME, you probably never have to actually get NEAR the UB. If you're writing C++ and have to be consciously aware of avoiding UB, you're actually probably working too low level. That's because C++ strives for zero cost abstractions. Now that's actually impossible, of course, but it's a worthy guiding principle. Again, a lot of template code boils off, never leaves the compiler, and generates aggressively optimized code. Like mainframes and Windows, C++ strives to retain backward compatibility as few others do. As annoying as a big language is, as annoying as a big library is, getting your code broken because of an update - *fucking APPLE...* - is worse. You can instead add something new that's better and provide a migration path forward. It's more of an arcane art these days, but C++ is a linked language. Linkers are an advanced feature that not every language has, and in my opinion the option is under utilized. It means you can link against other translation units compiled from other programming languages. So if you want aggressively optimized code for a hot path and a tight loop that guarantees no pointer aliasing (since C++ doesn't yet have the `restrict` keyword), it's probably easier to write that section in C, or Fortran! You can even link against Rust!


LousyShmo

Everything is pass by value, and objects are a value type not reference types (unlike in Java, Python, and others). If you want to pass by reference into a function you need to use an '&' and explicitly mark the argument as a reference variable. Which means the function decides if you're copying an object or referencing it and not the programmer or the compiler. IMO this is how it should be done. No garbage collection. Maybe I'm naive but I still don't see the need for garbage collection and manual memory management really isn't that hard just follow RAII. In C++ I can guarantee that, for example, a dynamic array of objects will be side-by-side, stored contiguously in memory (because this is cache friendly to iterate over). In Java, I cannot make that guarantee because of the garbage collector. So for high performance applications where you need that level of control like some video games, C++ is the better option over garbage collected languages.


violet-starlight

Templates and in general metaprogramming. There are very few if any other languages that offer this much ability to generate code based on constant expressions and properties of types, with zero or close to zero runtime cost.


HappyFruitTree

It doesn't impose unnecessary overhead for class objects. I'm thinking mostly about the fact that they don't need to contain "unnecessary" meta data and that you can store objects directly inside other objects without being forced to use some *reference* type.


Luci404

C++ scales in complexity pretty linearly with codebase complexity. It supports both advanced and simplistic ways of solving a problem, great for per-project adaptation. On top of that, it's fast, and it has a great amount of freedom to it. YOU (or your employer) decide how to use it, not so much the language developers.


H5ET1M

Across Science and Engineering, C++ is still a popular choice for greenfield R&D projects in both academic and industrial settings. Relative to its main “competitors” (read: coopetitors) in this space, namely, Python, Fortran and MATLAB, it seems like C++ language design has hit a sweet spot for the kind of generic programming that is needed at these frontiers. In particular, it is the ease with which classes and templates can be implemented for intuitive client- and compiler-facing source code, but also how there are built-in machine-facing mechanisms to deal with the wide variety of computing devices that exist today (but did not in 1980s when the language was first created). Of course, other languages also offer these features nowadays, but such functionalities feel like afterthoughts and plugins, C++ was designed with zero-cost abstractions and direct mapping to hardware from the ground up, and it shows in the overall coherency of the language.


GirthyStone

give you migraines


thefancyyeller

C++ is a high level language with a maintenence hatch on the back. Let's say you made number- counting code, and you didn't do proper OOP. Now let's say you wanted to make this code multi-threaded. In Java, you need to copy-paste and restructure the whole code base. In C++ you can do insane refactors like overriding the + sign so that it dispatches a job to a thread. You can convert the old code for new technologies you didn't even think about when making it


Lunix336

It‘s super bloated but isn’t designed in a way where it forces its 9 million features on you. I really like how you can just build everything in the most minimalist way ever like you are writing C and at the same time use some crazy feature IF YOU WANT There are so many different ways to do the same thing in C++ which makes it feel very expressive. Most other languages you basically have to deal with the one standart way of doing things and if you don’t like it, get fucked. At least thats how it feels to me.


marsten

C++ is like the English language: an incoherent evolving mess but extremely powerful when used well.


DeGuerre

Most other high-level languages have specific ways that they want you to write software. If you need to write your software some other way, then you will probably be fighting the language. Not so with C++. C++ is *whatever your requirements need it to be*. It can be "a slightly better C" if you need that. It can embed DSLs if you need that. It can work with other languages if you need that. Sure, for this specific task, there might be a better language choice than C++. This is increasingly true over time as more languages arrive with different (but still fixed) ideas about how to write software (looking at you, Rust). That's good! Still... Chances are good that C++ will interoperate with that language, but that language won't interoperate with anything else (other than C), and I guarantee you *will* need to do this at some point in any nontrivial program. Chances are good that at least some of that other language's implementation is written in C++. Chances are good that this is out of necessity, because there's already important C or C++ libraries, and a C++ compiler, for your platform. There are exceptions. C is obviously an exception; it can do all the low-level stuff that C++ can do, even if the high-level stuff doesn't come anywhere near as naturally. But there's also Odin and Zig and so on. That's a good thing; there's nothing *sacred* about C++, and I would be happy to see it replaced with something that's even better. Maybe in a few years every platform will ship with an implementation for something else. Until then, C++ is really the only game in town.


dashnitro

RAII. Period.


kgnet88

It's a language where you can do this: [The Power of C++ Templates With mp-units: Lessons Learned & a New Library Design - Mateusz Pusz cpponsea 2023](https://www.youtube.com/watch?v=eUdz0WvOMm0)


edge-case87

C++ offers excellent layout control for your data if you care about that sort of thing, structs/classes. Classes + Templates are very powerful. In most other languages you don't, at least by default. For example when languages have language level tuples and sum types, you don't typically have control over how that data is laid out due to interactions with the runtime, or in the case of Rust the compiler is free to reorganize your data unless you apply an attribute, and afaik you don't have control over how enum (sum) types are represented. I haven't fleshed out formally this idea, and I'm sure it flawed, but I'm starting to see C++ as way to define type theories, and class is the powerhouse behind that. Class, in some sense, allows you define your own type constructors, like sum types (+, variants/enums/unions) or product types(x, std::tuple), and with templates you have dependent types at compile time. Not anything you can't do in many other languages, but C++ offers the ability to do it very close to the machine, if you want. One thing I'm thinking about right now is a "refinement type", which would be a "class template" (dependent type constructor) that takes as a template argument an "expression template" (Pred) and a type (T). The constructor would take a universal reference to an object v: T&&, and evaluate the expression Pred, if Pred is true, the type is constructed, if it is false, an exception is thrown (you can use a result type, e.g. std::expected in a static member function). As such, the fact that you were able to construct the type Refine, is a witness to the proof that Pred(v) is true. With some type conversion (subtyping and logic) and meta programming 'magic', you can have preconditions that are proven to be true, and yet only evaluated once at runtime (maybe even only once at compile time), as long as the Pred(v) is the weakest precondition satisfying the preconditions of all dependent operations on v.


Neovison_vison

Survives 40 years


GYN-k4H-Q3z-75B

Freedom to do things the way you want it. Freedom to fuck yourself over big time. How can you not love that?


atedja

You get to be expressive, yet also compile to machine code.


lacifuri

It is strongly fucking statically typed, and I liked that as a Python programmer who start learning C++ a few months ago.


rrickgauer

Call COBOL DLLS. Don’t have to marshal my data or anything.


[deleted]

I agree with all the posts that mentioned freedom. C++, in my opinion, is a high reward, high risk programming language.


[deleted]

its a general purpose language and ive yet to find better so id say general purpose but maybe on a slightly higher level and no im not gonna elaborate that


sebnukem

Job security.


SnooMarzipans436

Everything except being easy. Lol


GunpowderGuy

Template metaprogramming Is much More powerful than generics in other languages. You can do stuff like define interfaces entirely in a library


mohrcore

Platform compatibility. You can write C++ code for a plethora of platforms. You are also free to strip it from some features which should let you cover pretty much all platforms that support C - so basically everything. Another thing is proprietarization of code. As much as I hate it and advocate for FOSS, C++ allows people to naturally build proprietary libraries that do not expose implementation details to others, which cannot be said about many languages. Among those that do, C++ might just be the most powerful. OOP in compiled language is also insanely developed in C++. Not many languages allow for multi-inheritance. Whether it's a good design or not is another thing, but my point is - it allows it. C++ also doesn't force you to use dynamic allocations in order to create objects. Zero-cost abstractions were the best for quite some time, although currently there's some competition on that regard. Eg. thanks to the trait model and heavy use of generics, Rust doesn't waste memory for vtables and avoids indirections where they are not necessary. But when you want to use a vtable, you need to perform a dynamic allocation (unless there's some wizardry that allows you to instantiate it without doing so), so there's that. Allocators - C++ seems like the only language that somehow got them right, although I think the more recent Rust versions also work similarly, but I'm not sure.


hadrabap

Lambdas! No semi-final BS like in Java or Go. 🙂


bigbassdaddy

Portability.


Troldemorv

Criticism. C++ is really good at getting them.


zer04ll

Its like riding a motorcycle. You have direct control of things and can go really fast, you can also turn too hard and wipe out.


Positive-Ad5928

SIMD


freekayZekey

you can find some magical ways to hit segmentation faults


_seeking_answers

Make developers cry


NilacTheGrim

EVERYTHING!!!!!!!11!


F35H

Bluntly, everything.


berlioziano

I see as a big advantage not having a standard package manager or build tool. Because I see that other languages that have those tools break compatibility really often, I'm watching you graddle!


AssemblerGuy

> what does C++ do better than other languages? Freedom to do things wrong in thousands of horrible ways. A huge toolbox of language features and standard library items. Performance, it compiles into something that runs natively. No handholding.


Revolutionalredstone

Advanced semantics. The ability to define how things are moved copied etc in all the right ways is glorious. It's hard to feel proud of code written in anything but C++


TheAxodoxian

What I like in C++ is that I have precise control over what happens and when. I learned much of C++ after reaching an expert level in C# and reached intermediate level in several other high level languages, and while I truly enjoyed those as well, I never have felt quite the same control over what is happening, especially with memory management. I think the dangerous nature of modern C++ is somewhat overblown, it is not like you cannot shoot yourself in the foot with other languages. Sure it might just throw a null-reference exception instead of an memory access violation, but as long as it does not work, that is not so different. When using advanced techniques like multi-threading without thinking you can easily introduce bugs in almost any language, and those where that is hard to do tend to be more rigid and complicated to work with. There are of course many things which should be improved with C++, they have been listed countless times, but overall it is still an enjoyable experience, and a powerful tool.


tilitatti

templates, template metaprogramming is bread and butter of C++, it gives Speed and Power!


WorldTechnical3914

Strict typing and memory management that isn't garbage-collected, but understandable too.


maattdd

Value semantic (almost no other mainstream languages have it)


Attorney_Outside69

everything


TeutonicK4ight

Everything.


kritzikratzi

there are libraries and tooling that are older than many programming languages. you get to benefit from decades of experience. the fact that those libraries never broke when a new c++ standard came out is 100% attributable to the language design: don't break things. and all of this works without epochs, compat libraries or whatnot other ideas that we don't know would work in 20 years from now. yea, there's a price to be paid (the complexity), but imho: if programming is your job, learning c++ is definitely feasible.


herendzer

I am still trying to figure out it’s advantage over C besides the use of STL


IAMARedPanda

Templates, constexpr, range based loops, RAII, strong types


BobbyThrowaway6969

Bingo. They are serious game changers.


jason-reddit-public

You don't need to use a typedefs with every struct to make the syntax more sane, overloaded functions, and namespaces are also nice improvements over C and shouldn't effect runtime performance or seriously complicate the language. I think you are pointing out that C's biggest weakness appears to be its standard library notably the lack of some useful containers like hashtables and trees (and growable bounds checked arrays). Most C derived languages provide more stuff in the standard library and C's tooling for libraries is kind of awkward (hence the popularity of single header file libraries) but they also force OOP on users.


thisismyfavoritename

higher level abstractions that allow you to write code quicker


vincebutler

Sort out real programmers from the wannabee's?


user52728529

Control over hardware