Tell me, which browser and operating system are you using to write this comment? It must be one written in something other than C++, right? Your browser isn't using WebKit or Blink by any chance is it??
Let's hope the web server or network appliances used to transfer the data to you are not using software written using this "deeply broken" language!
(Though I expect your parent has similarly negative views on C?)
I thought nginx was C++?
I also thought large portions of Windows are C++? Everybody loves COM!
(I used to work on ngx_pagespeed, which was a C++ server module that plugged into Nginx to rewrite pages so they would load faster.)
Did they approve of your module?
Windows is mainly C for the kernel, and C++ for the rest https://en.wikipedia.org/wiki/Windows_NT#Programming_languag.... That's around 90% of the desktop/laptop market.
IIS, Microsoft's web server, is C++ https://en.wikipedia.org/wiki/Internet_Information_Services. I think it is still the 3rd most popular web server in the worldwide.
There is code in Windows that was written yesterday and code in Windows that was written over three decades ago.
While not ideal exporting templates has been possible since Windows 3.1 days, as long as one sticks to a specific compiler.
/s obviously.
You're right that much of the software we use is written in C++, for good reasons, but asking people to "use a product of another language" just because they are critical (in a not so nice way, admitted) of it is going a bit too far. It's like asking someone to move to a different country because they think their system is "broken beyond repair".
I like that C++ allows us to express this situation, even if it's a bit of an unusual design pattern.
And also note that binding to the object at all has been possible only after C++11, while this "feature" works with earlier standards. That rules out the possibility of this being designed into the language with the express goal of achieving what you say (it doesn't matter, but just pointing out).
This isn't similar to C handles. There is usually a public API around the kind of the handle (e.g., the file oriented syscalls that works with file descriptor integers). In such cases, C handles are more like "this" pointers with an associated API.
Also, it cannot be the intent of allowing this pattern to implement opaque handles, as you can bind to them only after C++11 (auto), while such malformed code still compiles (including member access into the returned temporary) with -std=c++98.
The type of a lambda is inexpressible so they can only be handled with auto or decltype. I think that’s reasonable.
Traditional callbacks can also be used in this case, but what is a callback lambda but private state? And a stateful object rather than a lambda function is easier to manipulate, say by inspecting in the debugger or perhaps by providing a generic function for things like printing the entry.
Another case is where you have some hairball third party or legacy library that you want to be able to use in your modern code; you can often simply make it an opaque private object rather than making a complex visitor for it.
class Token {
virtual ~Token();
protected:
friend class MyClass;
...
/* all your state */
};
> what is a callback lambda but private state?You can (and do) program to the callback's interface -- say you ask for an std::function<void()>, and the user gives you that. What is behind the function (private state or not) is not your concern, you simply perform an public operation (calling it) on a public interface (i.e., via std::function).
Going back to the original point i was making with this example, I still think this was probably not a capability consciously designed in the language.
imo, the biggest issue with c++ is the lack of orthogonality. there is usually a "best" way to do something, but you have to read a lot to choose between the many other ways of doing it. the usual "best" way may not be applicable in your case because it is subtly incompatible with some older feature that's already being used.
as an aside, I always get a kick out of standard library functions like std::addressof. you have to use stuff like this in highly generic templated code because you can't be sure that some clown hasn't overridden the `&` operator for some type that will eventually be passed to your function.
I think that you overestimate how much Go and Rust are used in the wild, and how much of a threat they are to the C++ ecosystem. IMHO C++ is mainly competing with its own past.
That is not to say there is nothing good or beneficial about these languages, devs using them are free to evaluate the features provided and find that they suit their use case and go get to work. But some dev’s pet language, no matter how loudly they scream on Reddit and HN, is not yet threatening C++.
"Fixed" C++, per your description, already exists. It's called D. It's called Rust. It's called C#. It's called Go.
Meanwhile there appear to be many people who (I must admit much to my puzzlement) seem to still enjoy writing C++ and want to add even more features and paradigms to it. I wish them good luck and I'll be sure to look at the results from afar and see if I can recognize some bits of the C++ I used to write 15 years ago. Oh! I think I saw an "if"!
All of these languages with the exception of D are completely different. It's like saying you fixed a cupboard by replacing it with a sofa.
D's the most similar, but it's sadly not exactly a hot language or one where there's jobs available.
Or was it some other "manual" feature that's too much of a burden? Honestly curious.
1. Initialization
Type foo = Type(FieldType())
Type foo = Type{FieldType()}
Type foo = Type { .field = FieldType() }
2. std::unique_ptr can be null3. std::shared_ptr does not guarantee atomic reference counting
4. std::variant and std::optional require exception handling.
5. std::map should be the std::unordered_map data structure, while std::ordered_map should be the special case. The unordered_map should also stop being a terrible hashmap implementation on most platforms.
6. std::vector<bool> is not what you think it is under the hood
7. Explicit should mean the opposite when it come to single argument constructors (meaning implicit casting needs to be explicitly enabled in the constructor definition)
8. Although on that point, one could argue that implicit casting should be a different operator overload than constructor definition.
9. There needs to be a mechanism to check the validity of a template argument before the template is expanded (concepts will fix this, iirc)
10. https://codegolf.stackexchange.com/questions/1956/generate-t...
11. It should be trivial to implement an std compliant iterator. It is not: https://stackoverflow.com/questions/8054273/how-to-implement...
what would be the difference between a never-null unique_ptr and a reference ?
> std::shared_ptr does not guarantee atomic reference counting
is that a problem in practice ? all implementations do use atomic reference counting. Just because it's not written in the standard does not mean that common sense does not apply.
> std::variant and std::optional require exception handling
exception is the standard way to report errors in C++
> std::map should be the std::unordered_map data structure, while std::ordered_map should be the special case. The unordered_map should also stop being a terrible hashmap implementation on most platforms.
Anyone who has a problem that calls for caring between unordered_map and map will know the difference, and for everyone else, does it matter ?
My opinion on that is that standard library types do not really matter - I use 3 different non-standard map implementations for specific use cases in one of my apps and there is zero friction as maps are almost always an implementation detail, it is nigh uncommon to e.g. have an API that takes / returns maps.
> std::vector<bool> is not what you think it is under the hood
that depends on who you ask :p from past teaching experience, if you ask students to tell you what is vector<bool> they will tell you that it is packed because it feels like the logical thing to do.
> https://codegolf.stackexchange.com/questions/1956/generate-t....
turing-complete language can generate arbitrary things and is not immune to halting problem, news at 11 :p
Ownership.
> all implementations do use atomic reference counting
They do not.
> exception is the standard way to report errors in C++
Not really, at least in practice. Many C++ developers do not use exceptions at all, with good reason.
>turing-complete language can generate arbitrary things and is not immune to halting problem, news at 11 :p
The point is that a relatively simple syntax error on behalf of the programmer generates an incomprehensible error message. This is just a comical example of that, and a lot of real world code using templates is full of opaque errors at the start. That said, concepts should help eventually.
I enjoy C++. My general approach to programming is that you should make a domain-specific language to express your problem, and then solve it in that DSL. C++ is a good tool for that when you also need deterministic performance guarantees. So any "new feature" that allows me to write more expressive DSLs is welcome.
I used to be a C++ diehard, but modern C++ is why I started learning Rust. If I'm going to have to learn a whole bunch of new idioms and rules, I might as well do it with a language that has the new features and safety built-in, rather than bolted on.
You don't. Just because you bump a version number it doesn't mean you are forced to use all the bells and whistles.
It doesn't. If you have any experience working on C++ projects you will be very aware that deciding which feature is and is not used is the kind of stuff which is defined in the project's coding guidelines docs, along with naming conventions and choice of build system.
With C++ you only have to use a feature introduced after C++11 if you decide you really want to use it. Some projects even in this very day still don't use smart pointers or exceptionsor std::array. Some people still do the old C with classes thing.
Moreover, the world does not come to an end if you arrive at a project and need to learn a feature provided by a programming language.
And you will find that you have to learn these features once they are allowed in the guidelines. Some workplaces stick to the old features. Some regularly update with pushes toward use of modern features. When your coding guidelines prefer modern C++, you have to learn it.
Which is why C++ is dying and those other alternatives are finding so much appeal with new generations of programmers.
Then I kind of grew frustrated by the complexity and super long build times and for a few years I left C++ on the side, going back to C and other languages. Now I'm a big fan of Rust.
These days when I see a modern C++ codebase using "auto" all over the place, lambdas, the new constructor/initializer syntax, std::move and more, it can be very tricky for me to understand what some code is doing. I feel like I'm reading a new C-based language where I can understand most of it but I feel like some key components are eluding me. Generally I end up figuring it out but I really don't feel comfortable modifying the code because I don't understand all the implications. Very few languages, especially as old and huge as C++, change so drastically and so fast.
And again, I considered myself an advanced C++ user not so long ago.
>With C++ you only have to use a feature introduced after C++11 if you decide you really want to use it.
If you're the original developer who makes the decisions. If you end up working on a project using a different subset than the one you're used to then you're screwed. That's what the parent is talking about.
> These days when I see a modern C++ codebase using "auto" all over the place, lambdas, the new constructor/initializer syntax, std::move and more, it can be very tricky for me to understand what some code is doing.
But what if you had spent 1/10th of the time you spent learning Rust looking at these features (frankly looking at the wikipedia pages for each revision is enough most of the time I think :
https://en.wikipedia.org/wiki/C%2B%2B11
https://en.wikipedia.org/wiki/C%2B%2B14
https://en.wikipedia.org/wiki/C%2B%2B17
https://en.wikipedia.org/wiki/C%2B%2B20
)
You can write object-oriented code in C too (e.g. gtk, glib etc). It just involves much more boilerplate, and it doesn't offer the same amount of built-in safety guarantees.
So I know enough Modern C++ to use it, but why would I when there are far better alternatives?
For example, try to use Rust to implement a UWP component callable from .NET, interacting with the Visual Layer, while using mixed mode language debugging inside Visual Studio.
It's the way a professional software developer who actually works with C++ projects looks at C++.
> More than a decade ago (pre-C++11) I used to be a pretty proficient C++ developer. (...) Then I kind of grew frustrated by the complexity and super long build times
Honestly, that comes out as utter bullshit. It sounds like you tried to find out which were the cliche criticisms and mindlessly repeated them, without noticing none of it makes any sense.
The main "complexity" that C++11 added was smart pointers and threading. It is simply unbelievable how someone who parrots they switched to Rust claims that stuff such as smart pointers and threading is too complex to learn. It's the sort of stuff that any developer quickly picks up with a cursory glance through the docs.
Your whole statement is even less believable if we were to believe your claim that you were somekind of Boost wizard who "considered myself an advanced C++ user", because Boost is the staging ground for whatever was added to the C++ standard.
Quite honestly, I find it hard to believe any of your claims.
The same could be said of English. Would you switch to another language because someone uses a word you have never used before?
But I want to use those features. I want memory safety and a way to say this variable owns the memory, vs that variable which is only borrowing it. I want move semantics in some cases and copy semantics in others. I want lambdas so I don't need to define new functions (or classes) to handle simple visitor patterns (or other cases where passing a 'function' makes sense).
These are good, useful features that I'd like to use to make my code more safe, more performant and more readable, and while C++ can do these things to some degree, there's boiler plate and new rules (rule of 5 vs rule of 3) and gotchas, compared to a language like Rust that has these things built in, with more safety and without compromising performance, and for me it made sense to start using it instead.
I still have projects in C++ that I'll maintain with modernish C++ rather than re-writing them, but for new things where I have a say in the matter, I'll choose Rust.
I don't think that is happening in Rust.
I have not (C++14 onwards was roughly where I started paying less attention), and that was partly my point. C++ has gone through dramatic change, and if I'm going to go through that dramatic change, I might as well do it with a language that has modern features and safety built in, and doesn't require extra boilerplate to do it.
Looking up the rule of zero, it seems there's still some debate about whether it's a good thing or not [0] (don't know if it's been resolved yet), and it still doesn't preclude you from knowing about the rule of 5 and the side-effects of declaring or not declaring certain operators/constructors/destructors.
> As the language gets more capable, the code you write gets simpler.
> I don't think that is happening in Rust.
This happens quite often in Rust, see for example error handling and the evolution of the ? operator, and the recent addition of async/await, and unlike c++, as the language gets more capable the changes required in terms of coding style and updating your mental model of how things work is usually not so dramatic.
0: http://scottmeyers.blogspot.com/2014/03/a-concern-about-rule...
Scott has retired. The better alternative to his suggestion was noted right there in the comments. Rules of 3 or 5 concern only designers of a library, and if you are designing a library, you may ignore them now.
The net number of people adopting C++ in any unit time dwarfs by orders of magnitude the number adopting Rust; and the number already using C++ exceeds that of Rust by many more. That will remain true for a long time. As a consequence, any improvement to C++, either core language or library, has overwhelmingly larger lasting real-world benefit than any corresponding feature in Rust.
Rust pursues benefits by making a class of low-level errors hard to express, at some cost to expressiveness, and at quite substantial cost to adopters who must learn to work around the limitation (which they do). Against such cost it provides some convenient new control flow features, and leaves behind many C and C++ misfeatures that C++ cannot.
C++, instead, pursues benefits by making the language increasingly able to capture semantics in libraries, and thereby deliver thoroughly optimized and tested semantics to users without compromise. The result is that C++ users, by using such libraries, are able to code at a level high above that where the bugs prevented by Rust would manifest, and write less code that could harbor bugs of any kind, overall.
It is not clear whether adoption of high-level coding practices by coders using or switching to C++ will produce more benefit than those adopting Rust, and coding without access to such libraries. I have placed my own bet, and we will see.
But we can say with certainty that every coder who switches to modern, safe C++ from C or C-like C++, or to Rust, is a net win for humanity. And, if Rust in the end fails to grow out of its boutique niche (which is still absolutely possible), everyone later leaving Rust for C++ will bring to it high expectations that will incrementally raise the quality level of new C++ code.
Bad-mouthing of C++ by Rust fans may feel good, but it causes a net harm to humanity by the degree to which it reduces the number of coders who switch to modern C++ from C. The number of C coders who switch to Rust, instead, is far, far too small to compensate for such harm.
So the only defensible, responsible behavior is for C++ and Rust users to promote C++ and Rust (not necessarily in that order) and concentrate on getting coders off C.
In fact, I believe that in terms of developer time wasted as well user frustration, C++ is the most harmful language in the history of humanity. Someday I'll put together a page listing the dozens of C++'s design daults. Here's just a single article demonstrating how incompatible with simplicity and correctness C++ is: http://www.icu-project.org/docs/papers/cpp_report/the_anatom...
Colloquially and practically, I might suggest that it demonstrates that the programmer may be dangerously thinking in C with little lumps of data as their classes. The programmer is thinking and coding in C, with some classes, that they then feed to a C++ compiler.
People were doing it like that back in the nineties, when what we think of as "modern C++" didn't exist.
I don't see where is the problem. Perhaps, you could give an example of the equivalent code in your favorite language?
The large number of remaining C coders, and the ease of switching incrementallty, means that the number switching to C++ is always overwhelmingly larger than the number adopting Rust from all starting points.
We may lament that they do not start writing modern, high-level C++ immediately, but the number of CppCon (and similar) talks hosted on Youtube, and rocketing attendance at, and number of, such events, shows that there is great interest in learning good modern C++.
It's pretty old and somewhat outdated by now, but you might enjoy the C++ FQA (Frequently Questioned Answers):
The reality is that C++ is still an extremely unsafe language, where any slight deviation from strict discipline (discipline that itself has only really been ergonomical since C++14 or so) will lead to memory corruption errors. Even with modern C++ features you can get memory corruption: null references, references to moved objects, no way to signal errors from destructors, and there is still no good way to check whether an operation on ints will overflow. Moreover, the insistence on optimizing around undefined behavior, specific to C and C++ I believe, coupled with large reliance on undefined behavior in the standard, leaves C++ in a very poor position as far as guarantees of safety are concerned.
In general, the responsible thing if we want a more secure world would be to discourage the use of manual memory management as much as possible, whether it be in C, C++ or Fortran. That does include trying to get people to use smart pointers if they absolutely have to use C++, but it should also include getting people to use other languages if at all possible (Java, C# or Go would be the more mature ones for large business).
Modern C++ is just not a safe language to program with. It is very easy to produce errors that result in segmentation faults, and it takes great care to produce code that works properly even with shared_ptrs and unique_ptrs and so on.
But you are correct that adoption of C++ is higher than Rust, and will continue to be so until some mission critical framework or for example game engine starts to support Rust in as a first citizen language.
Until then, we have modern C++, with all it's quirks and difficulties and lost developer time in figuring out where the hell was that dangling pointer or why the heck was an object not freed correctly, or why did the array access or vector access go off by some value.
Not saying C++ isn't good, it is, but a lot of time is wasted figuring with C++ currently when a lot safer alternative could be used. Unfortunately that is not very realistic in many scenarios yet, although I carefully evalulated Rust also for my current project, the requirement of supporting a C++ game engine just outweighs easily the hassle of having to figure out bridges and bindings and such.
It's when you switch to online multiplayer and end up having to maintain and modify code written by other people who have different opinions on how kitchen sinks should be installed and used that things tend to sour a bit.
Alternately they're iteratively evolving the language as each generation of features are fleshed out? They've been doing this for several decades now. It's their job. And for those people using C++ tooling, or working on C++ projects: Cool, new stuff to ease some edge conditions.
RR makes excellent aircraft engines, for both Boeing and Airbus https://en.wikipedia.org/wiki/Rolls-Royce_Trent
Modern C++ is already a large improvement over C, which was already a 19th century carriage, when everyone was moving into steam cars.
However, I don't see many companies throwing away their IDEs, game engines, build systems just like that.
It is easier to migrate those teams to static analysis tooling, than throwing it all away and start from scratch in another ecosystem.
Hence why both Microsoft and Google are still two major contributors to ISO C++, in spite of being in the process of adopting Rust.