Hacker News new | past | comments | ask | show | jobs | submit login
C++ Initialization Story (reddit.com)
70 points by _hao on March 28, 2023 | hide | past | favorite | 103 comments



C++ is my daily language. Has been for my entire career since the mid 90s. About 10 years ago I gave up trying to understand it all and things have been fine. Good even. Even more so since I pushed warnings to max (where possible), tooling like clang-tidy, -format, and all the other static analysers, multiple compilers on multiple platforms, and extensive use of tests and so on. You know, general best practices. To the extent I've forgotten loads of things.

So what I want to say is, it's not necessary at all to understand the language completely or even mostly in order to do good, high quality, productive work with it. Not even close.

Maybe with the advent of AI tools like co-pilot I can even start to forget more ;)


This comes back in comments on HN regularly: 'I use this or that daily and I like it' . Be it windows 10, linux, Android, Rust. If you use something daily for 30 years, there is a LOT you know about it. You forget how much you know about it. Probably you type and read std:unique_ptr<> as fast as you can type an asterisk. All those best practices exist for a reason, and one of the main reasons is that it is such a convoluted language that even compiler makers have trouble understanding the spec (hence multiple targets, linting etc). So kudos to you!


No this is not true and it's actually a common misconception. It is not true that doing something for a long time makes you better at it or more knowledgeable about it. There is an excellent meta-analysis [1] that looks at domains such as music, games (such as chess), sports and other domains that shows that people must put in deliberate practice and make an explicit effort to improve, otherwise they simply stagnate and get into a bit of a comfort zone with little to no improvement.

When it comes to programming I often say that there is a difference between someone who has ten years of actual programming experience, and someone who has two years of experience that they just repeated five times.

I can state from experience that there are plenty of C++ developers who have been using it for decades who don't know basic things about it, and use it like it was still 1995.

[1] Deliberate Practice and Performance in Music, Games, Sports, Education, and Professions


This is a very fair point that I agree with and in retrospect I wish I had emphasised the limits of what I was trying to get across. But your and other replies have done it for me so I'll leave it as it is.


What you are describing is the desire to rely on your tooling and tests, and you should be able to. Unfortunately, in the 25 years I've known C++, I feel like I've been promised this and that and the other thing was making C++ safe, correct, reliable, etc. And yet this goal seems elusive. I'm glad that you don't have to think about most of the language these days, but there are too many trapdoors and landmines waiting out there, and in C++ they have serious consequences. There are bugs in the code--probably in your code--right now. Some might be CVEs because of how little guarantees you have when you stumble into UB. I hope we get past the "works for me" and realize the downstream implications of software being riddled with potentially serious bugs that result from a ton of complexity coupled with explosive consequences.


I guess you can still write valuable software, even more complex than most people can write in a lifetime, with simple (03) C++. Like Doom 3: https://github.com/id-Software/DOOM-3-BFG

> What you are describing

On the other hand, while I think you have the best intentions, I believe what you are describing is also the exact meaning of FUD. In that precise order: "in C++ they have serious consequences" is Fear, "There are bugs in the code--probably in your code--right now" is Uncertainty, and "Some might be CVEs" is Doubt.


I guess. The other day i created a PR to turn some macros into a variadic template and got a compilation error that can be resolved by moving some functions around. No one could figure out why so i just closed the PR.

There are so many moving parts in C++ there’s a reason why there are dialects. People are manually having to choose the smaller C++ that they can manage.


> I think you have the best intentions, I believe what you are describing is also the exact meaning of FUD.

FUD usually has a negative connotation as a disingenuous form of rhetoric. If your assume the poster is genuine, then you shouldn't in the next breath accuse them of spreading FUD. If one is genuinely fearful and uncertain and filled with doubt, it's okay to express that.

To the parent's point, C++ does allow programmers to easily write code that crashes spectacularly. Such bugs have been shown to cause catastrophic failure in critical systems, to the point where we decided to build languages and tools that mitigate those modes of failure. Those learnings have found their way back into C++, but the problem remains that writing modern C++" is an ever-moving target, and the "legacy C++" that should be avoided is still there in the name of backwards compatibility, so buggy code still being written. The solution is not "just write modern C++" because that doesn't work; witness the lamentations here about people who are still writing C++ like it's the 90s.

As for the uncertainty, the only problem with that statement is the "probably" because we all know the only bug-free code is trivial code (and even then...). But still, there's an important point here: shouldn't we be able to confidently make statements about our codebase like "there are no bugs of X type in here, because it's been checked by tools". For example, some languages are stricter with what they will allow past the compiler, and the level of strictness confers some guarantees about what kind of bugs have been checked. If we can't say "my language's tooling makes it so my program doesn't suffer from X bugs", then how much is it helping us really?


Bah, 2/3rds of CVEs are buffer overruns that cause RCE. That doesn't occur in memory safe languages. I mean, you can juggle double-ended chainsaws on fire as a party trick, but probably not recommended for daily activities.


> 2/3rds of CVEs are buffer overruns that cause RCE

Is this the "70 percent of all security bugs are memory safety issues" article people like to link every time?

If so, it's not 2/3, it's 70%. They are not buffer overruns, but memory issues, and not all can cause remote code execution.

There is no rule that says that fixing bugs is an itch and everybody has to disperately scratch it, and some people can sleep well at night even if they have a few bugs. The rest is FUD in favor of one or another language flavor.

Not all software has a remote endpoint, is connected to internet, has an UI, or process input, etc. C++ and "juggl(ing) double-ended chainsaws on fire" is not the same and is an unfair comparison.


One of the better known buffer overruns (Heartbleed) was build on top of what boiled down to buffer reuse, which is common even in memory safe languages.


There's no obvious way to write the Heartbleed mistake in Safe Rust.

In C it's really easy, a trivial mistake, you just don't check the payload length and copy blindly, but in Rust you can't write this mistake at all, so you'd need to re-architect the system to make it possible to leak this data or else (if you're not actively trying to leak data) you just don't do this and you can't be attacked this way.

The closest analogue, Rust's [T].copy_from_slice wants a slice of the same size, so if we try to make the mistake OpenSSL made where we just forget to check, that means the slices are the wrong size and we panic, it's a Denial of Service but nothing more.

If the slice is the right size that's a normal heartbeat, everything works as intended.


It is also really easy in C to have a safe abstraction for buffers that check payload length and does not copy blindly. Why so few people use such abstractions I do not know, but I guess once Rust is more widely deployed, we will also see a lot of unsafe Rust where people did not have enough time or energy to do things properly.


> I guess once Rust is more widely deployed, we will also see a lot of unsafe Rust where people did not have enough time or energy to do things properly.

This doesn't make a whole lot of sense. If you lack "time or energy" you're not going to put the extra work in to write unsafe code.

In C this bug was much easier to write than the correct thing, whereas I explained in Rust the bug is much harder to write than the correct thing. Humans are lazy so they're going to tend to do the thing that's easier, and here (and in many cases) that's the more correct thing in Rust but not in C.

This is just ergonomics. Notice how crash bars work on fire exits for example. Even people who are panicked and just running into the doors will trigger them to safely open outwards. You get incident reports where operators locked the fire doors, trapping people, or incidents where there are just too many people to evacuate despite the fire doors working for those who reached them, but you don't get incidents where people are like "Huh, I have no idea how to open this door, these crash bars are too difficult for me to understand".


You are right that one problem in C is that it is too inconvenient to do the right thing. A safe buffer abstraction should be included in the standard library. Still, I already saw bad Rust code using unsafe. I wonder how it came into existence when not by lazyness?


I am far from a rust expert, but from a short look at stackoverflow copying between two slices of different sizes seems to be a for loop away and I saw no mention of unsafe.

> so you'd need to re-architect the system to make it possible to leak this data or else (if you're not actively trying to leak data)

OpenSSL called, your standard library sucks and it is going to provide its own significantly worse replacement for everything you can think of and at least ten things more.

> you just don't do this and you can't be attacked this way.

So it is a drop in C replacement.


> I am far from a rust expert, but from a short look at stackoverflow copying between two slices of different sizes seems to be a for loop away and I saw no mention of unsafe.

You can do this, but, what are you copying and why?

The C code is just trying to copy the expected amount of data from the receive buffer into the send buffer. Under attack the receive buffer is actually nowhere near big enough to do that, but C doesn't care, which is why Heartbleed exists.

You can't write that mistake in Rust, even if you insist on painstakingly writing it out as a for loop, if we have a 20 byte receive slice, and we ask for receive[1000] that'll panic

To leak the data in Rust, you need to re-architect the software, you need to consciously plan for leaking the data in your software. "This code is to help us leak important secrets, and then this structure here enables the leaked data to be fed into data sent to an attacker".


> Unfortunately, in the 25 years I've known C++, I feel like I've been promised this and that and the other thing was making C++ safe, correct, reliable, etc. And yet this goal seems elusive.

How hard have you tried?

The tooling is terrible to set up, and build system integration is extremely lacking. But once you have set up clang-tidy and clang-format, it just works, and it catches bugs and ensures a consistent style. And enabling clang's and GCC's static analysis is just a few compiler options away. Same with address sanitizer, leak sanitizer, UB sanitizer and thread sanitizer.

None of it gets used automatically, you have to understand the tools and how to integrate them into your build system. But they're not at all elusive.


> There are bugs in the code--probably in your code--right now. Some might be CVEs because of how little guarantees you have when you stumble into UB.

Pick any medium/large project written in any language that hasn't undergone extensive formal verification+testing and this statement will likely be true.


This won't quite be true for Safe Rust because it doesn't have Undefined Behaviour. So while it's possible there are bugs, and it's possible those are security bugs, they can't be caused by UB as they would often be in C++. Your program had defined behaviour - it's possible this behaviour wasn't what you intended, but it's what you wrote.

A lot of cases which might invoke UB in C++ will just be a Denial of Service in Rust, as you panic because an unhappy path wasn't catered for properly in your software and most likely your panic handler just terminates the program. That DoS might still be a CVE, but it's probably not the severity you'd have seen for the equivalent C++ bug.


I am the maintainer of a very large scale multi-threaded C++ application used by large airline/airport/rail companies around the world. I haven’t had a bug in production for 5+ years. Not one. And I routinely refactor/improve large parts of the code with zero problems.

The “secret” obviously is 9000+ system level tests.

And I will claim that you need that number of tests. Even if the application was written in (say) Rust. Rust won’t save you from subtle daylight savings errors, country specific governmental requirements, weird special case organisational policy rules etc. Only an executable spec (tests) will do that.


I've also spent a decade writing almost exclusively code in C++.

After a decade, there was no end in sight on all the obscure patterns and way of doing things provided by the language. After a decade I realized that the more I learned about the language, the more I needed to know. And that's when I called it a day and promised myself not to touch this pile of smoking crap even with a stick in my career. I write code because I like to build things that solve real problems, not because I like to jerk myself off on all the possible theoretical ways to initialize a variable or a pointer.

If you need to read tons of fat books to be aware of all the nuances of the language, then the language has failed its goal of being a useful tool to build things.

And where are the advantages given by all the possible types of memory allocation, pointer declaration and variable initialization? C++ is still a memory-unsafe language, after all. So you still have to handle most of the low-level complexity of C, while getting a language polluted by four decades of patches and crap, and having to read big books just to understand how initialization and pointers work.

No wonder that C++ is increasingly becoming a relic confined to the cemetery of bad technological ideas, no new software is being built in it at all, and Rysy and Go are eating all of its cake.


> If you need to read tons of fat books to be aware of all the nuances of the language, then the language has failed its goal of being a useful tool to build things.

You should probably judge usefulness the language by how much software was produced using it.

> No wonder that C++ is increasingly becoming a relic confined to the cemetery of bad technological ideas, no new software is being built in it at all, and Rysy and Go are eating all of its cake.

Do you have any data to support this? Where i work (one of FAANG) we don't use Go at all and rust is limited to only certain types of applications. Other stuff is either python or c++.


> You should probably judge usefulness the language by how much software was produced using it.

Then Fortran and Cobol are probably the most useful languages (and maybe Java can be on that list too), but can we say that they're actually loved by those who program in them, or that they offer a modern and fast way of building software? Eventually, how much software was written in a language is mostly a function of how long that language has been around.

> Do you have any data to support this?

Just pick any news article about any large projects migrating from C/C++ to Go/Rust. C/C++ have historical issues with memory management that make it too easy for the code to blow up. The vast majority of CVEs is about vulnerabilities caused by improper memory allocation, deallocation or assignment. And, in order to mitigate some of those issues, C++ has become so complex that it makes it harder to shoot your foot, but easier to blow up your own leg. Sure, all FAANGs have been writing most of their core software in these languages, but they've also invested a lot of resources in building alternative languages that were simpler but equally performant/expressive.

Keep in mind that FAANG companies have to onboard hundreds or thousands of engineers, and the cost of getting somebody to be proficient in Go, Rust, Python or Kotlin is much, much lower than getting somebody to be proficient in C++ - and, most of all, to get somebody in a position where they can reliably push code to production that doesn't blow up.


> Just pick any news article about any large projects migrating from C/C++ to Go/Rust.

Judging usefulness of a language based on news article doesn't sound like a good idea to me.

> Sure, all FAANGs have been writing most of their core software in these languages, but they've also invested a lot of resources in building alternative languages that were simpler but equally performant/expressive.

Sure they invested in new languages but don't forget they also invest much more in existing ones.


> Then Fortran and Cobol are probably the most useful languages

There are a lot of critical bits of software written in Fortran. I don't think there is that much Cobol still running around though.

> and maybe Java can be on that list too

Of course java is an useful language!


A lot of concepts first seen in Fortran, or popularized by Fortran are now in other languages or making their way there. In my personal opinion, even if you will never use Fortran professionally or at work I think it's worth learning at least basics. It's actually a very simple language.


Fortran is a simple lovely fast parallel language. That is my opinion after 20-years of professional development in more than half a dozen languages.


Real low-level assembly language probably is easier to really understand and reason about than C++, isn't it?

I used to code in C++ with Borland C++ Builder and it felt almost the same like doing WinForms with C# pracrtically but once you want to really understand the language and what's going on the deeper level C++ seems infinitely obscure.


> Real low-level assembly language probably is easier to really understand and reason about than C++, isn't it?

No. There's no comparison. Assembly is far harder.

Assembly can be completely unstructured. It can jump into the middle of a subroutine. OS permitting, it can be self-modifying. You have to have a very clear understanding of how each instruction can affect the condition flags. Instead of getting very familiar with the C++ spec, you're getting very familiar with the chip spec.

You can write clean, understandable assembler. To do so, you have to have self-discipline. You have to resist using all the things that the assembler makes possible. But you can do that in C++, too - and should.


It's hard to judge. They're both potentially too complicated to understand, and in different ways. I think we probably have to give it to assembly as easier though.

There's no IFNDR in assembly. (Ill-Formed No Diagnostic Required: the C++ get out which says well, this isn't a C++ program and so it has no defined meaning but your compiler probably won't even warn you about that, so your code does compile it just has no defined behaviour)


There is absolutely IFNDR in assembly. Your assembler isn't going to warn you if what you wrote will segfault or otherwise blow up. You can happily use opcodes that are not valid on your target architecture revision.


There is. It's called "undefined opcode".


Undefined Opcodes are just like C++ UB. They're very bad news, but they're nothing compared to how terrible IFNDR is. I think C++ programmers either don't realise how bad IFNDR is, or they just don't want to think about it. IFNDR means your entire program is always meaningless.

Let's take a UB example, an IFNDR example, and an undefined Opcode example and compare the potential consequences

1. UB example. We have a program which does some work in a loop, the user can select how many times between 0 and 256 the loop should execute. Unfortunately this should have been limited to 255 times, if the user picks 256 the loop exit condition is always false. In C++ this is Undefined Behaviour and the program's behaviour is arbitrary once that arises.

So long as you never select 256 in the loop iteration setting, this program is fine.

2. IFNDR example. This program only lets the user select between 0 to 200 iterations. Unfortunately if more than 10 iterations are used the arithetic inside the loop uses a std::vector of floating point values with an algorithm specifying that the values are std::totally_ordered, as a result this is IFNDR because floating point values are a structural match, so this compiles, but they aren't a semantic match for the total order concept and that's IFNDR. Even if the feature is never activated and nothing is ever processed with the std::totally_ordered algorithm, the behaviour of the entire program is undefined, the program has no meaning at all.

Running this program at all could cause anything to happen.

3. Undefined Opcode. This time the program has between 1 and 100 iterations, it's written in assembly but unfortunately due to an oversight for the odd numbers of iterations the undefined Opcode GLARK R0,R0 is executed which only works on a model of CPU which you don't have. This program misbehaves, perhaps spontaneously rebooting or showing other bizarre behaviour - but only if that Opcode is executed, which for even numbers of iterations never happens.

So long as you only use even numbers of iterations, this program is fine.


If you have examples of #2 happening, in production code, from production compilers, then we might start to care. Examples, plural. Not just a handful, either. Enough examples that it becomes a statistically valid actual concern for those of us writing C++.

Otherwise... yeah, theoretically there could be monsters hiding under your bed. To be really safe, you should throw out your bed and sleep on the floor. But you're not going to, because the threat is theoretical but not real.


What would an "example" of these facts about how C++ is defined even mean? As you've observed, you don't care anyway, you can clamp your hands firmly over your eyes and see no evidence of a problem.

The Committee doesn't need to write more, and more, and more IFNDR into the language standard - there are other ways forward, but it's easier and C++ programmers have had their hands clamped hard over their eyes for decades at this point so why not ?


1) data races are undefined at the hardware level

2) poking at random memory mapped hardware registers can produce such forms of UB that C++ can only dream to.


> data races are undefined at the hardware level

Um, what? To have a data race you need a formal model that doesn't exist for the hardware.

> poking at random memory mapped hardware registers can produce such forms of UB that C++ can only dream to.

When they say "Undefined" they really meant it, C++ UB is allowed to do MMIO, or whatever else.


> Um, what? To have a data race you need a formal model that doesn't exist for the hardware.

Intel and other manufacturers do provide a model for their hardware (although it is a relatively recent thing and has been formalized outside of intel).

> When they say "Undefined" they really meant it, C++ UB is allowed to do MMIO, or whatever else.

Well, I do give you that.


Code written in the standard of C++ of 20 years ago (pre-c++11) does not even remotely look anymore like today's code conforming c++17. (let alone 20 or 23). Understanding it only got harder over time.


Std lib level code for sure. Application level is easy to grasp if written by decent programmer.


However, Application code is calling all these nightmarish library functions which you don’t understand and have to rely heavily on documentation and experimentation to use. It’s not like that at all in e.g. Java, where reading the standard library code is a pleasant and educating practice.


This is good because unlike Java, for C++ there are several standard library implementations so relying on something that happens to be guaranteed by one is not a good idea. The standard and documentation is the only place where you will find what is actually guaranteed to work.


Please stop this FUD. I have zero trouble using std::whatever in C++ without diving into their code. Usage is very well though out and user friendly. Higher level libraries do use templates on a different level and are very readable.


> Real low-level assembly language probably is easier to really understand and reason about than C++, isn't it?

I've often thought that. If nothing else, if a given opcode (say, an ADD) is being used, things like integer wraparound are going to do something specific and well defined, not cause undefined behavior and invalidate the entire execution of your program. I miss that from my 6502 assembly programming days :-).


>"So what I want to say is, it's not necessary at all to understand the language completely"

I agree. Same here been using C++ forever, first as "C with classes" and then "modern C++" and whole bunch of other languages as well. I have general understanding about "big" parts but I learn specifics on on need basics and yes tooling / internet search helps greatly.

I manage to write software that works reliably and do not sweat over those FUD spreading prophets telling me that my software will self explode every other day.


Right - the vast majority of C++ enhancements since 2017 (maybe 2014, or even 2011) arn't even targeting application developers - they are meant to support libraries.


What amazes me about C++ is that the complexity is deliberate. I started learning it voraciously in the early 90s, read Design and Evolution of C++ and many other books. Over and over again the theme was to be broad and deep, multi-paradigm, kitchen-sink approach that should have as much power as possible, with the bizarre caveat that it had to be backwards compatible with C (mostly).

I have never understood this POV, but to understand C++ O think you need to grok this key point deeply.


as someone that has been using c++ since the late 1980s, can i observe that about 75% of c++'s features are aimed at library writers? most people writing application code simply do not need to know the syntax or the semantics of this stuff - these are all features that make c++ libraries simpler, easier and more efficient to use, mostly transparent to the library user.


Yeah this is definitely true. C++ clearly doesn't like "special" features like Go's map, which only the Go authors can implement. As a result it has a ton of features that are extra complicated in order to let you design easy to use APIs.


very true. there is almost nothing in the c++ standard library that you cannot rewrite in standard c++. actually, i think nothing.


It's not nothing, there are numerous intrinsics needed, and also "hacks" where the standard library does something that's labelled UB if you did it in your code but is magically blessed OK when the stdlib does it.

That preference to solve things in "the" library leads to other horrible problems though, where C++ ought to have a first class language feature, but instead WG21 has enshrined a workaround in the library which is probably better than if you'd made your own, but rather poor compared to a first class feature.

Take the array. Rather than provide a good array type in the actual language, C++ offers std::array, a library class in the standard library. But this standard library class isn't available in "freestanding" C++ while the builtin C-style array is available. So you end up with awkward syntax and the core language loses flexibility.

Likewise strings, in Rust the type of an arbitrary literal "Hacker News" is &'static str, a reference to an immutable view of this text which lives as long as necessary. In C++ the type of "Hacker News" is char*, a pointer to bytes. C++ 17 at last provided std::string_view which is the thing you actually wanted for about two decades, but the type of "Hacker News" isn't string_view it's still char*.


i have no idea why you think the standard lib is less blessed than the language.

> In C++ the type of "Hacker News" is char *

Nope it is at least const char , and if you want to assign it to a variable it is:

   const char * const hn = "Hacker News";
jesus, the hn formatting with this is driving me mad


HN thinks asterisks mean you want to emphasise text (these days using italics) so you should in most cases escape them with a backslash.

Much of the C++ standard library (including for example std::array) is not available in freestanding C++. Should it be? Perhaps. But it isn't.

In contrast to Rust's conscious decision to provide core, alloc and std as separate layers, in the C++ there's a rather ad hoc process to decide what's freestanding.


> In C++ the type of "Hacker News" is char *

In fact it is not:

  int main() {
      auto&& x ="Hacker News";
      x.foo();
  }
<source>:6:7: error: request for member 'foo' in 'x', which is of non-class type 'const char [12]' 6 | x.foo();

They are an unstable type (an array) that, because of its C affinity, tends to quickly decay to pointers, hence the need to use ̵a̵ ̵p̵a̵r̵t̵i̵c̵l̵e̵ ̵a̵c̵c̵e̵l̵l̵e̵r̵a̵t̵o̵r̵ the universal reference to observe its fleeting lifetime.

edit: can't speak English


Good point, I should have remembered these are actually immutable arrays of char (with a bonus 0 byte at the end).

The main thrust of my point though is that this type is terrible - even before it decays, and you don't get a std::string_view which is what you probably actually ought to get in modern software.


> C++ 17 at last provided std::string_view which is the thing you actually wanted for about two decades

Err..string_view was available in Boost for quite a while actually - at-least for a decade as far as I remember, possibly more. There are so many missing features in Rust that are only available in crates even today: sane error handling for one/custom allocators for another, but god forbid if you criticise Rust on that basis. You will get downvoted to oblivion.


I don't see how string literals end up in the same category as custom allocators. Maybe you write some very special code which rarely uses strings for anything but needs a lot of custom allocators, the vast majority of programmers, even C++ programmers are very much the opposite.


Indeed but the hassle of using Boost and the hassle of using a Rust crate are a little different to put it mildly.


Afaik it is just some (quite a few) type traits, like std::is_class and such that you could not write yourself without compiler intrinsics.


dunno - far beyond my pay level. but:

https://en.cppreference.com/w/cpp/types/is_class


Sure, but now you have to implement is_union (I guess 'not is_class' is not going to work :) )


I remember somewhere in one of my undergrad courses textbook that had a quote to something of the effect that C++ was a federation of languages. And honestly, it still feels like that all these years later. It's both a blessing and a curse depending on what you need to do. Most folks probably never venture fair outside their specific subset of C++ to use anything else and probably an unlucky few have to have an esoteric level of understanding the language to do their work. I don't envy the latter.


Agree 100%


https://images.app.goo.gl/osKiAwVKrqof2DeL8

Animated image, no more comments needed


I can't believe a 300 pages book is needed to just talk about initialisation in C++!!! Now I understand why Linus refused this craziness in the Linux kernel. I genuinely believe that C++ is just a toxic wasteland of time. It's not even that productive, fun to work with or secure. I would take C, Rust, Golang, Python anywhere, anytime.


Linus refusing this in the kernel arguably set it back quite a bit IMO. Lots of the kernel is the kind of "simple" you only get with C i.e. macro hell and lots of repetition. For example with a proper C++ class you could make /proc/ output a proper format seamlessly whereas with C you basically have to either write a fuckload of scaffolding or just repeat everything.

Also you can write a full book just about C pointers, it's up to the author how far they can stretch it.

N.B. I also am not a huge fan of C++ but certainly for the past 10 years I think it's a net loss not using it.


Linus objected to C++ partly because it has far too much implicit allocation.

If you look at how much surgery is required to make the Rust for Linux alloc work you can see he was quite serious. For example Rust for Linux Vec::push doesn't exist, because if the Vec wasn't big enough that's an implicit allocation, instead Vec::try_push is provided, which is fallible.

There was nobody proposing to even attempt that kind of work for C++.


Linus refuses to use C++ because he literally believes us C++ programmers are subhumans.

I don't think his position is entirely rational (and, understand, I have otherwise huge respect for him as an engineer).


C++ doesn't have any implicit allocation. The standard library does but that is no-go for the kernel anyway. Doesn't preclude using templates, classes and other C++ features in the kernel - and some external proprietary drivers already do.


> I genuinely believe that C++ is just a toxic wasteland of time. It's not even that productive, fun to work with or secure. I would take C, Rust, Golang, Python anywhere, anytime.

Please reconsider bashing it that much, if not out of respect for the people who use this tool daily, then out of the observation that the program you used to write this message was probably written in or uses libraries written in C++.

It's a powerful tool and has been used to create amazing things in competent hands, so maybe its flaws, that we like to bash so much, are a great thing - it's what drove people to create all this other languages that we love to experiment with.


C++ has it's ups and downs.

It's still semi-compatible with C, templates are about as close to macros as you'll get with a syntax; and the algorithms parts of stdlib are in many ways brilliant, thanks to Stepanov.

But the complexity is definitely overwhelming.


I suspect that the complexity of C++ is mostly a reflection of complexity of software engineering in general.


C++ isn't a person, and so we're not hurting its feelings by pointing out that it's terrible. If we hurt Bjarne's feelings by criticising his baby I'm sure he'll get over it.

I don't see much difference between pointing out that C++ is a bad idea despite the fact that some good software was written using C++ and pointing out that slavery is a bad idea despite the fact that some famous US landmarks were built using slave labour.


You know, you can replace "C++" in your comment with "PHP" and it would still be just as correct. But that doesn't make PHP (or C++) any better than it actually is.

Also, "reconsider bashing it that much, if not out of respect for the people who use this tool daily", wow. Surely you don't mean that respecting people who are in a tough situation (e.g. having to write C++ daily) involves never pointing out that the situation they are in is, indeed, tough and could be better?


You don’t need these 300 pages. It’s not because a book is that long that it is needed. It’s a niche book for C++ enthusiasts, like the book on std::move (one that I personally enjoyed greatly)


Which one is that? I'd like to check it out.



I doubt that it is strictly _needed_. Most C++ programmers will probably live life gloriously without having ever read it. But if you really want to know every nook and cranny of C++ initialisation (which I sincerely hope I will never want) then it seems like a great thing that this book exists!

Niche knowledge is fantastic for those who want it or need it. No need to knock it just because you don't.


> I genuinely believe that C++ is just a toxic wasteland of time. It's not even that productive, fun to work with or secure. I would take C, Rust, Golang, Python anywhere, anytime.

Specifically compared to C, there's a reason so many people switched to C++. They weren't sheep. They weren't just following marketing. If you don't understand what was better about C++, then you're criticizing from a place of ignorance, which is not likely to provide valid criticism.

Now Rust, Go, Python... there are reasons at least some people switch from C++ to those languages.


> Now I understand why Linus refused this craziness in the Linux kernel.

Here's the old post for reference:

https://lkml.org/lkml/2004/1/20/20

Also, one for git:

https://lore.kernel.org/all/alpine.LFD.0.999.0709061839510.5...


It's not needed.

There's a lot of extra fluff like examples and such beyond the basics of C++ initialization.

Also seems to have relatively little text per page in the Amazon preview [1].

[1] https://www.amazon.com/dp/B0BW38DDBK?asin=B0BW38DDBK&revisio...


Sure but at the same time, the author says the book started as a blog and some examples, and “before you know it” was 150 pages. To me, you should have been able to write all that needs to be said about initialization several times over with that much space, let alone 150 pages more!


It's not to just talk about initialisation in C++, it's to to just talk about modern initialisation in C++! Imagine how much more ther is if you wanted to know everything about initialisation in C++ not limited to the modern things.


i doubt that torvalds (or you) has ever written a significant program in c++. if he has, where? and if you have not written a significant program in a language, you do not get to judge it.


linus has subsurface


meaning what?


Meaning that he has written a significant program (called Subsurface) in C++.


so, let me get this straight. he wrote an application for a dangerous pastime (diving) in a language that he has many times publicaly despised? cool.


The mention of the number of pages seems passive aggressive.

Here's what the book actually covers and it is "initialization and related areas" which you could fill many pages about any language if you include examples, a quiz, some foundational chapters:

The book contains 14 chapters in the following structure:

    Chapters 1 to 5 create a foundation for the rest of the book. They cover basic initialization rules, constructors, destructors, and the basics of data members.
    Chapter 6 is a short quiz on constructors. You can check your knowledge from the first “part” of the book.
    Chapter 7 Type deduction: auto, decltype, AAA
    Chapter 8 describes Non-static Data Member Initialization (NSDMI), a powerful feature from C++11 that improves how we work with data members. At the end of the chapter, you can solve a few exercises.
    Chapter 9 discusses how to initialize container-like data members.
    Chapter 10 contains information about non-regular data members and how to handle them in a class. You’ll learn about const data members, unique_ptr as a data member, and references.
    Chapter 11 describes static non-local variables, static objects, various storage duration options, inline variables from C++17 and constinit from C++20.
    Chapter 12 moves to C++20 and describes Designated Initializers, a handy feature based on similar thing from the C language.
    Chapter 13 shows various techniques like passing strings into constructors, strong typing, CRTP class counter, Copy and swap idiom, and more.
    Chapter 14 is the final quiz with questions from the whole book.
And there are two appendices:

    Appendix A - a handy guide about rules for compiler-generated special member functions.
    Appendix B - answers to quizzes and exercises.


Ha. I'm quite happy that I started off my career coding in C++ and then subsequently moved away towards web tech. It's nice having appreciation for the lower-level aspects of PLs, but I feel more comfortable working at higher levels of abstraction and being able to make full-featured products with less effort, thanks to an abundance of computing power in most computers.


>abundance of computing power in most computers.

[citation needed]


Maybe I overgeneralised - I had most personal computing devices in mind, which I'm most interested in developing for. I appreciate that there's orders of magnitude more computing devices that do not fall into that category.


In my opinion as a non-professional hobbyist developer and a software "consumer", the main problem of current software trends is that they rely on computing power too much. I understand why a developer might want to quickly implement and test an idea using high level languages and no optimization. However, it feels like nowadays, developers are not moving on from the "rapid prototyping" stage to the "optimization" stage, almost like abandoning a project, yet they always keep adding new stuff.

We are heading for a personal dystopia of mine everyone's attention spans are too short in every aspect of the life. People are addicted to new stimuli, whether it be the next 1 minute video in the timeline, or a new feature for the software that will never be "mature" due to all the other new features.


I think there's value in taking a balanced approach to writing software - use high level PLs and their frameworks but use them well (i.e. take the time to learn them and their patterns, and not just hack away). This way we're not excessively wasting resources doing redundant processing and we're not stuck for hours trying to squeeze every last bit of performance out of the cpu. I get your point about not advancing from the prototype stage in terms of the codebase, but if it's 'good enough', then there are always more important problems to tackle.

As for your second point, it's already been happening for quite some time. Can we blame people though? Every product we use is engineered to perfection to beat human psychology and make us indulge more and more. It's hard to protect yourself against something like that if you realise this is a problem, let alone if you don't. It doesn't just apply to technology but other areas too, take food for example.


I keep reading how C++20/17/14/11 is entirely different.

I've been programming in C++ since 2004, involved in Boost then the standards committee. For me there hasn't really been such a big change, it's always the same language at core, with a few evolutions, that mostly make it slightly more terse.


IMO move semantics, auto, lambdas and smart pointers have changed the way we write C++ dramatically. I work on both old and modern C++ codebases and the difference is like night and day...


I think I'd just give up and become a baker or something if I had to go back to pre c++11.


Smart pointers are not a language feature, and are generally a bad practice (shared ownership is a bad idea to begin with).

Lambdas, just syntactic sugar for function objects.

auto, you could just spell out the type and provide a mechanism to deduce it (e.g. the old result_of protocol).

Move semantics, this is simply distinguishing lvalues from rvalues in overload resolution. There were other ways to do that before albeit not as accessible to the layman.


I generally disagree with your assessment, but the following needs to be called out in particular:

> Smart pointers are not a language feature, and are generally a bad practice (shared ownership is a bad idea to begin with).

Smart pointers don't imply shared ownership, see std::unique_ptr. Or is std::unique_ptr considered bad practice as well? That would certainly be news to me ;-)


std::unique_ptr is of course the opposite of shared ownership, in that it requires you to explicitly transfer ownership if you need to do that. It's a beautiful feature which improves code clarity and reduces bugs.


Yes! Also, it significantly reduces the need for user defined destructors and move constructors/assignment operators.


Here's the direct link to the blog post on the book:

https://www.cppstories.com/2023/init-story-print/

And the book at Leanpub:

https://leanpub.com/cppinitbook




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: