Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

As a talented C++ developer... yes there is a dearth of talented C++ developers.

I've been to several C++ conferences. Even there, many of the engineers end up learning "new" things that are IMO basic concepts that have been around for years.

I recently went through a hiring phase for Senior C++ engineers and most of the applicants were familiar with old tech. It was really disheartening to me to realize how many "senior" C++ engineers weren't senior in real C++ experience. Even one of the hires ended up using a C style array in their first commit instead of std::array.

It's really frustrating and makes me wonder if perhaps I'm in the wrong job: maybe I shouldn't be a software engineer, maybe I should be a software educator to teach modern concepts and un-teach ancient concepts. Indeed, a lot of the ancient concepts directly contribute to the modern world's problem of software safety.



I can't help but wonder if developers are simply off-put by the complexity of the language itself.

Way back in 1989 I was fortunate enough to get Borland's C/C++ compiler, the K&R C book, and Stroustrup's C++ book - which, at the time, was about the same size as the K&R C book. The C++ language was relatively simple to learn at that time: no STL, no odd pointer types, no template metaprogramming, etc.

Fast-forward to 1997 and I'm listening to a talk about C++ compilers and hear that templates are now a Turing-complete language, and how the compiler developers used the template language to coerce the compiler into printing out the prime numbers.

Fast forward again to 2022 (with trips to Java, Kotlin, Scala, and Haskell in between) and I've got a project that requires JNI and Python bindings to a core C engine. Great, I'll use C++! I proceed to start searching for containers/constructs and realize that at least 50% of the C++ language and standard library is unreadable to me. I only have a guess as to what a `shared_ptr` or `unique_ptr` type is, and I certainly don't know when to use them, and concepts/traits outlined in the STL documentation seem to be some sort of generalizations that the STL might provide default implementations for, but might not? What exactly is the syntax and/or type of a lambda function and how do they interact with C function pointers? etc., etc.

I get the sense that C++'s evolution has been driven by esoteric corner cases that a handful of developers have encountered and the language & STL design has been driven by those cases. I'm still surprised by how many problems I can easily address in something like Scala or Haskell that C++ simply does not provide the facilities to express easily.


> I can't help but wonder if developers are simply off-put by the complexity of the language itself.

I certainly fall into this category. At one point I could have almost been considered a C++ language lawyer.

But then two things happened:

(1) I got stuck working on codebases that assumed C++11. Even now, I'm using Python3 and C++ (mostly 11, with a little 14/17 sprinkled in).

(2) The C++ language spec got significantly more complex after C++11. Without writing C++14/17 code on a regular basis, I just couldn't justify the time spent trying to keep up with it.

So for me, the cost/benefit ratio of trying to stay "current" with C++ is no longer worth it. I expect to prefer Rust over C++ for new projects.


> I only have a guess as to what a `shared_ptr` or `unique_ptr` type is, and I certainly don't know when to use them, and concepts/traits outlined in the STL documentation seem to be some sort of generalizations that the STL might provide default implementations for, but might not? What exactly is the syntax and/or type of a lambda function and how do they interact with C function pointers? etc., etc.

And that's exactly my point though! `shared_ptr` and `unique_ptr` solve (or, at least, simplify) a lot of the memory management problems endemic to all C code and old C++ code. And they've been around for over a decade now.

I would absolutely be willing to spend some time with you to teach you what new things are, what they do (and what problems they solve), and how to use them without introducing new problems. I think several one-on-one teaching sessions would help you a lot with that. But one-on-one teaches you and not the thousands of other old-experienced C++ developers also in your shoes.

> I get the sense that C++'s evolution has been driven by esoteric corner cases that a handful of developers have encountered and the language & STL design has been driven by those cases.

While some of the C++ evolution fits that category... I would also add that a lot of changes in modern C++17, C++20, or C++23 are aimed directly to the masses of C++ developers doing "everyday" work. shared_ptr and unique_ptr are definitely not esoteric corner cases: they're driven to specifically solve memory management problems that have directly contributed to some very significant CVEs in many thousands of products.


A series of expert-level blog articles guided by your experiences teaching a pre-2010 C++ guru would probably be well received by other such "ex-gurus." They would need to be definitive, detailed, verbose and bring the reader up to C++ lawyer in the relevant new feature to be interesting.

A trip through the graphics pipeline has the correct level of detail:

https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-...


I tried to find a book which assumes knowledge of and experience with C++98 and brings you up to speed as far as C++17. Do you know of such a thing?

I read some of Effective Modern C++ but it seemed to be more a list of footguns and poor design decisions in the later C++ editions.


> Do you know of such a thing?

I'm afraid I haven't read any C++ books. I'm sure that's where some of my strong biases come in; I'm all self-taught with some cppcon videos and attendance sprinkled in for topics that I know I'm weak in.

I can recommend a Slack [0] or Discord [1] though. There are plenty of other C++ people who can make such recommendations.

[0]: https://cppalliance.org/slack/

[1]: https://www.includecpp.org/discord/


C++ has fantastic docs, books, videos, so much. You shouldn't need to read the std library code, and shouldn't read it to know what is safe to do. There are many implementations and they differ in details but all have really good standards compliance, except where they document deviation (like EASTL omits some slow stuff).

If you want to iterate over a container, know promises about algorithmic complexity, have strong guarantees about type safety, or know what smart pointers promise to do then you can get all that without digging into the stdlib's code.

I know this wasn't the main point of your comment but shared_ptr can be thought of as a reference counted pointer. It cleans up the pointed to object when all the pointers to that object go away. It doesn't need to be reference counted, there are implementations that do goofy ring lists under the hood but all the operations on it are cheap O(1) operations and it is only slightly slower than a raw pointer, looking at the code might cause someone to miss the promises of computation complexity. For object you only want one of there is unique_ptr. You give it a pointer or constructor to make an object and when that pointer leaves scope it cleans up the object. Both are great for managing things like memory, connections, file handles, anything you want automatically cleaned up when the pointers leave scope.

Not all languages have the robustness that comes with a 40 year history, so learning last year's hotness and C++ are going to be different.


I'm with you mostly, although as the mostly sole maintainer of an 22 years old and still evolving C++ codebase (among some other responsibilities) I do try to keep up with the language. But if I didn't feel this was necessary for my job I probably wouldn't do it or at least won't sink too much time into it.

I've also programmed in Haskell and I've had the same reaction as you, as to the things I can easily express there and not in C++. However I think the 2 cultures (Haskell and C++) are similar in that they both attract people who like to produce clever code which is unreadable to other people, even though the base language is not that complicated.

As for your questions:

1) shared_ptr / unique_ptr: Personally I liked this presentation. Watch it on x2 speed until it gets to parts that are difficult for you.

https://www.youtube.com/watch?v=xGDLkt-jBJ4

2) lambdas:

https://www.youtube.com/watch?v=3jCOwajNch0

This is more dense than the previous one. As for your question "how do lambdas interact with C function pointers": rough explanation is they are not the same, since they can possibly allocate memory if they capture. But if they don't capture anything they are just like a (static) function, and can be converted to a function pointer.

As for concepts / traits, rough answer is that you don't need to know about them for everyday work, unless you write a library / API for consumption by other C++ developers. In that case, they help the compiler provide better/shorter error messages in case template functions/classes aren't used properly.


Excellent videos and thank you for sharing them!


You can do almost anything in C++ at least three different ways. Most places that care about engineering will not have you do abusive template metaprogramming or go crazy with macros, even though it’s possible to do in the language.

The std library is filled with bad implementations that can’t change because of backwards compatibility. So it’s not your fault that they look confusing. The pointer types you mentioned are actually quite simple, think of them as thin wrappers over raw ptrs with constructors/destructors that implement counting (for shared ptrs) and whose destructors do the delete operation (for unique ptrs, and for shared ptrs once they reach 0 copies).

Working with C++ can be easy and fun as long as you aren’t in a codebase where people went overboard with anti patterns or “cleverness”.


The odd corner case is called data structures... and linear algebra, and memory management!


so you have java and python and c, and then you decide to add c++ to the mix? not sensible, imho.

and nobody is forcing you to use lambdas - you can do everything with other language features


To be fair and assume competence: A lot of C++ programmers have been burned by adopting the latest and greatest bling, then having to port it to some backwards platform that doesn't have a recent compiler. Many of us use the legacy stuff when possible, because we know it works, there are already robust third party libraries that interoperate with the legacy stuff, and it is more likely to be portable than std::omfgbbq.


This is getting better. Businesses that force a specific compiler for reasons other than technical merit are being punished in the market.

I am currently at a not super advanced C++ shop that has to write for several compilers on locked platforms, and even the worst/oldest compilers are clang or gcc forks that support C++17 and some C++20. We have robust CI and if it passes there we can use it (presuming it doesn't violate style guide/best practices/code review/etc). It is unlikely we will be burned by adopting the latest thing for anytime longer one developer is working on it.

I think the companies that are so afraid of upgrading software tooling and related processes incurred huge project costs because of otherwise needless major rewrites. One I worked for a college bookstore management software developer that was trying to rewrite their whole point of sale software. They were simply crushed by tech debt. Any fix in the original software took months and the rewrite wasn't finished before the company was bought by a competitor. Better unit tests, better practices staying up to date, better CI all would have contributed to business success.


Raises hand. Everyone needs to read "Effective C++", which is mostly a book about how not to shoot yourself in the foot with C++. The book is old enough now that the way he recommends writing C++ wouldn't make it into a PR.

So for that reason, I tended to write C+, which is pretty much C+, with some classes.


after rereading effective c++ with a decade away from c++, my main takeaway is that c++ shouldn't ever be used. The title should be "55 reasons to not use c++ for your next project"


I find that argument funny, given that Rust can't be updated often enough before every other library breaks.


That's the problem with the C++ ecosystem, it is actually many vastly different ecosystems mashed together. It's impossible to find a "C++ developer" because there is no agreed upon "one C++ style". It seems what you're looking for is a "C++ developer who likes to write the same C++ style as myself" ;)


> It seems what you're looking for is a "C++ developer who likes to write the same C++ style as myself" ;)

No, I'm perfectly content with someone writing C++ in a different style.

What I'm not content with is someone who uses old code without a technical reason why. C style arrays, for example, are 100% inferior to std::array. Old loops with indices are maybe 80% (off the cuff guesstimate) inferior to ranged-for. There's absolutely no reason whatsoever to use `delete` in any C++ code that doesn't directly handle allocations (and so, very esoteric), and simlarly for `new`. But I keep seeing these things (and many other examples) show up in newly-written C++ code from "experienced" developers. Maybe 90% of the time they'll fix their code when I point out the modern solution and what problems the modern solution solves, and the last 10% of the time ends up in a technical argument about the merit of the old code (and that's fine as long as there is a technical merit for it).


> C style arrays, for example, are 100% inferior to std::array.

Are the advantages of std::array over C arrays big enough to add 8kloc to each compilation unit though? (https://www.godbolt.org/z/8noTndhcv)

A range-checked std::array replacement can probably be written in a few dozen lines of code.

That's the problem with all C++ stdlib headers, they are incredibly overengineered for what they bring to the table.


> Are the advantages of std::array over C arrays big enough to add 8kloc to each compilation unit though?

I say yes, absolutely. C style arrays are _very easy_ to get wrong in many ways. Three just off the top of my head:

- iterating using a size_t instead of an iterator

- calculating the size of the array (and often using a preprocessor macro to do it)

- leaving things uninitialized

So a std::array provides iterators and works with a ranged-for loop. The only reason to use a size_t is if you truly need an index number (and I would argue: use `std::distance()` instead).

A std::array provides a `size()` giving the total number of objects in it. It also provides the type, so you can do sizeof(type) * array.size() -- though that's still error prone.

A std::array ensures that objects are correctly initialized.

And, if you still need to dangerously decay the data to a pointer, you can use .data() to grab that pointer.

> A range-checked std::array replacement can probably be written in a few dozen lines of code.

Can you provide an example?

> That's the problem with all C++ stdlib headers, they are incredibly overengineered for what they bring to the table.

I would argue that the standard library isn't overengineered. It's engineered for more than just your use case. Just because code "is there" doesn't mean that code makes it into your product. Pay for what you use, don't pay for what you don't use.


Last time I needed to write `delete` I was either fixing some low level garbage code that was super old or writing a smart pointer for a case not handled by the standard library. Either way it was so long ago that I really can't remember which.

Complaints about delete aren't about part of common modern C++, if they aren't from subject matter experts aren't well structured complaints.


Last time you needed to, sure. The problem is that if you find out how to do dynamic memory allocation, there will be tons of resources pointing at new/delete. Parts of the language that all the experts agree are terrible are just sitting there, poking out behind a shiny facade, waiting to scratch the unwary.


How is that not the case for any language that lets experts get at the gory details what is the alternative?

Even in languages like Ruby this problem exists. Superficially, Ruby has a decent garbage collector and you never need to dereference a pointer. In practice as soon as it gets slow you hit an optimization stopping point and need to write an extension in C. Then you have all this mess again except with all the baggage another whole language brings to the table and none of the sheltering of a type system.

At some point you just have trust software devs to use the tools.


holy mother of god! I used C++ around 2000 for some old projects. When new and delete where the object oriented "equivalent" for malloc() and free(). So, if you don't use that, what do you use in 2022 C++?


`std::make_unique()`, `std::make_shared()`, or another function that wraps `new` and `delete` into an RAII type (commonly called a smart pointer) so that you, the developer, worry less about explicit memory management.

And the standard smart pointers are perfectly extensible enough to wrap things allocated from C libraries (I like to pick on opengl's glalloc() and glfree(), though malloc() and free() are acceptable to pick on too), C-style `FILE` pointers, or even memory-mapped things from `mmap()`

I would also point out that even in 2000, `std::auto_ptr` existed. So even in 2000 you probably should not have been using `new` and `delete`.


std::auto_ptr was broken and didn't work with STL. It wasn't until C++11 introduced "move" semantics that you could really use smart pointers.

You can't really blame him for not using a part of the language that was unusable, right?


By the GP's opinion, you use the stl classes that implement RAII for you.

What is, obviously, only one way to do it, with its up and downsides. Granted that the upsides are much more numerous than the downsides, but there is a reason it's not the only option available.


> C style array in their first commit instead of std::array.

In my neck of the C++ woods, neither are a good choice. My point is: C++ is not a language, it is a language group.

Most north Europeans speak a Germanic language, which have many shared features and often partially shared dictionaries, yet they mostly won't understand each other without some further study. As a Dutch speaker I can't judge the quality of somebody's German, even though it sometimes feels like I should be able to.


> In my neck of the C++ woods, neither are a good choice.

Just off the top of my head: "it's not resizeable" (use a std::vector instead) or "it's allocated on the stack instead of the heap" (you can use a std::unique_ptr<std::array> to put it on the heap). But what are the reasons to not use `std::array` in your neck of the C++ woods?

> I can't judge the quality of somebody's German, even though it sometimes feels like I should be able to.

The cool part about software languages is that they're implementations of data structures and algorithms. Understanding those gets you most of the way to understanding what the code does regardless of whatever native language is spoken.


I've had the same experience in Java. Experienced engineers that are learning "new" Java even though those features came out years ago. I really think this will be the case for any language. Most people are not the HN type that are going to live and breath programming.


The ones on HN that actually work don't have the time to run after every few language feature either ;)


I prefer to be proud that I've never touched Java... for Old Reasons. But that said, it's a valuable language.

It's nice to know that other languages have similar problems :)


I'll probably get down voted, but I honestly really enjoy Java. The language, while it has some legacy verbosity, is in my opinion the perfect balance of simplicity and complexity. It has just enough language features without becoming Scala/Rust/C++ levels of complexity, while still being competitive on performance.


The reality hammer hits quite a bit harder when people are playing the "fake it until you make it" game with C++ versus other languages as well.




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

Search: