We have C++14
isocpp.org
isocpp.org
I like way more of C++11 than I liked of the prior version, but there's just so much that's accumulated over the years. I wonder if breaking backwards compatibility is the key, but then I look at Python 3 and think, well, probably not.
* Don't use var
* Don't use dynamic
or even better,
"You've only got .NET 2/3 installed"
Still no exceptions, though.
The thing is, when you have a single codebase that is maintained by thousands of engineers, you have to make concessions. There is no place for "rockstar programming": everything must be, in a sense, bland, so that it blends seamlessly into the work of thousands of others.
I don't really understand organisations that still use C++ in 2014 but then knock out such fundamental parts of its functionality, but then looking at the design priorities for Go, clearly at least some people at Google have very different preferences to my own, so YMMV etc.
In any case, the decision was made, and we have millions of LOC where every single API is built with the assumption "No exceptions here." In that context, introducing exceptions seems suddenly a lot more trouble than its worth. Well, YMMV, and in any case I'm not a decision maker so what do I know.
* BTW, I think "a single codebase maintained by thousands of engineers" is the single best thing I found in Google, as it opens up infinite possibility of learning new tricks, new APIs, and sometimes new projects. (Of course, everybody complains that every API is implemented at least three times, but imagine how worse it would have been if every project had its own codebase.)
Also no exceptions implies no failing constructors which is plain ugly as a constraint.
In general if you're going to work with other people I believe you need to be a bit flexible on coding with them rather than trying to be hard headed about your own style. It's important that people not be surprised when they work with your code.
I do the same thing. Not because I can't write C++11, but because I still encounter systems with older compilers that I want to run programs on. What, is this surprising?
Let's face reality: it's a little unreasonable to expect every system you work on to have a compiler less than 3 years old.
Especially true on older Linux systems, it's sometimes a massive pain or even pretty much impossible to upgrade the existing compiler in a package-manager-friendly way (try upgrading Ubuntu 12.04's compiler to GCC 4.9, for example), so you'd have to compiler the compiler from scratch. Which is a pretty massive PITA and more or less requires a PhD of its own for GCC (Clang is a little better). And on Windows VC++ isn't always exactly following the correct standard. It's not necessarily outright impossible, but it's pretty impractical.
If you are running Linux, this is one thing that Windows gets right. (Although as you say VC++ has some catching up to do still).
For example I had a building machine running RHEL 5 which was building for both RHEL 5 and RHEL 6 while using gcc 4.8.2 for both (cross compilers).
See also https://en.wikipedia.org/wiki/Cross_compilers#External_links
I've hand-built GCC for half a dozen of different target architectures over the years and it's perhaps one of the most stable pieces of software when it comes to building it. I've only had one build failure over the years and that was unstable from git (even that usually works no problem).
To build GCC, follow the simple steps on the GCC manual. With a modern fast computer, it's all done in an hour or two (of mostly waiting).
If you're dealing with bare metal projects (kernel programming or micro controllers), building binutils and gcc for cross compiling from source is pretty much required. There are scripts that help and some distros have cross compilers in their package managers.
But building GCC is not difficult and it pretty much works first time, every time.
This is your problem.
Build a new compiler using the old compiler and install the entire new toolchain in /opt/my-gcc-4.9-0xfoof . rsync this new compiler to any machine you want. The package managers (people and code) a here for our suffering.
I don't think the idea is to force existing software to be rewritten. It's to provide a clean break so that new software isn't saddled with the baggage of the old. Over time, most of the older software is retired or replaced, and the industry migrates to use the better tools with more and more projects.
This seems a very reasonable strategy, as long as your ABI or equivalent interface specifications can remain compatible for the common subset of functionality, so that programs built using the new language can still use libraries written in the old one. (See also: Every successful general purpose programming language in decades has offered a FFI for C.)
It doesn't work so well if you don't have proper formal standards for your old and new languages. It's also much harder to achieve in practice if your code is effectively running on some sort of virtual machine so you can't have that clean break at the ABI level, which might be one reason why several languages have failed to make a convincing big jump in recent years (Perl 6, Python 3, etc.).
With this argument, every release that adds a new keyword (for example) would have to be given a new name, since it will very likely break some code. Question that remains is how much must the changes be before the thing deserves a new name.
That said it's quite expressive now, you can do a lot with a little code, which is always nice.
Perhaps we should start with dispelling the old notion that one "shouldn't use" the STL.
Real-world C++ is an array of sometimes mututally-exclusive dialects, patterns, rules, sub-dialects.
Reading MFC is nothing like reading Qt which is nothing like WxWidgets which is nothing like Boost which is something (but not quite like) the STL which is way different from Apache C++ libs which is way different from what Google's C++ libraries are...
This is what happens when a language is "un-opinionated", throws everything including the kitchen sink at the language, tries to compile C and legacy C++ while introducing new features oh and also can't break existing code.
It's on its way out, no doubt about it. And we'll be better off as an industry for it, I'm sure of it.
Rust, Go, and others will be there to fill in the gap in a much better, saner, safer, maintainable way.
MFC was the vilest, most horrible abuse of C++ from the day it was released. Anything that involves MFC should just be rewritten with C# or turned into a webapp. I wouldn't take a job that involved programming MFC.
And of course, if you admit that exceptions aren't worth worrying about, then you'll start to question the entire "C++ way," which usually ends in disillusionment.
Alternatively, instead of disillusionment, you may still kind of enjoy C++. But suddenly you find that it's been three years since you've worked with C++, and on reflection, you haven't really been missing out on much of anything at all by not using C++.
It doesn't seem like C++ solves the right problems, even with the new dialects. Programming languages should be convenient to think in. By immersing yourself in the C++ mental model, it becomes difficult to keep a large-scale architecture entirely in your head.
In my experience, this is literally backwards. RAII is the only way to make exception-safe classes that aren't a gigantic mess.
> It doesn't seem like C++ solves the right problems, even with the new dialects. Programming languages should be convenient to think in.
No, some progrmaming languages should be convenient to think in. Some need to be uncompromisingly fast. C++ is in the latter set and nothing more convenient to think in is faster.
Yes, and C++11/14 make significant strides toward being more convenient to think in as well, without compromising speed. In fact some improvements also improve speed in some cases.
I wouldn't call Herb Sutter's _Exceptional C++_ a huge tome and it seems to be the standard treatment of exception safety.
I'm not saying it's impossible to write exception safe code. I'm saying that you can write code without exceptions without being worse off for it.
So I'm curious about why you think RAII makes writing exception-safe code difficult?
The book is excellent. For anyone who wants to use C++ exceptions, it should be required reading. But as someone who has gone through that gauntlet, I feel that I probably would've been better served by spending my time on something other than mastering the finer points of exceptions.
The reason I started talking about C++ exceptions in the first place is because, in my experience, when someone is very pro-RAII (like the original commenter I responded to), they also tend to be pro-exceptions. This isn't always true, but on average, it seems like either people prefer both or prefer neither.
Writing exception-safe code is certainly one of the hardest challenges available in C++, so if you enjoy a good challenge, then it's hard to do better. But if you're just looking to design large-scale systems, it seems like exceptions are unnecessary, as Google has demonstrated by banning the use of exceptions in their codebases.
In my experience, by refraining from using exceptions, it's possible to design large codebases more quickly, with fewer bugs, and without losing any safety or extensibility. However, this is simply my personal experience, and it may be mistaken to generalize this into a claim that all codebases among all C++ teams should refrain from using exceptions.
So, that's all I meant. I was also in excruciating pain yesterday due to a certain tooth that decided to segfault in my mouth, which may have contributed to the adversarial nature of my writing style. I feel bad about how I came across, and I sincerely apologize for it. No excuses, though: I should've done better.
exceptions (specifically, exceptions from constructors) are part of what RAII is, so it's only natural that people "prefer both".
As another personal anecdote, in my experience working with a large (175MLoC at last count) mostly-C++ codebase, I can't imagine how painful it would have been if the code didn't use exceptions.
I can't understand how a correct init method could be easier to write than a ctor, given that the compiler is required to generate code that knows which of your base classes and fields are already initialized at any point they could fail, which you would have to do yourself after moving to an init method, as well as losing the guarantee you can't silently ignore an error by forgetting to check for it.
"That's why C++ is overly cumbersome unless you ignore most of its capabilities, like exceptions."
Complete non sequitur. Exceptions are not "most of C++ capabilities". In fact, you can refuse to catch or throw exceptions for 99% of your (millions of lines) of code and still end up with a very large, stable code base running a large portion of the internet. Ask Google.
Today, there's pretty much no viable alternative to C++ for writing large scale, high performance systems with reliable performance guarantees. You could do it in C if you have a religious anti-C++ agenda but that would be like cutting off your nose to spite your face, and you'll end up in a horrible mish-mash of macros and generated code all over the place for a project with any level of complexity. Rust or D might get there some day if they manage to attract a solid community and big corporate backing. But they are certainly not there yet.
The point is that these features are infectious. If you don't want to throw exceptions, how do you handle a failure in a constructor? And then if you abandon constructors, other C++ features are unusable without them. And so on.
To add to this point: There are C++ frameworks such as Qt who don't use exceptions at all! And what impressed most: When writing a Qt application, you don't even miss exceptions. You don't have to resort to C-style return value checking all over your code. How is that? It took me some time to figure this out, but I believe it is because Qt applies the "Null Object" pattern consequently - down to the deepest depth of their framework,
Have a look at Tarsnap's source code.
True on my case, now using the language mainly on hobby projects, although we are very good friends since 1993.
Personally I would like safer systems programming languages from Mesa branch of languages had more use in the industry, but OS vendors decided to embrace C instead, and we ended up in the exploits everywhere that we enjoy nowadays.
C++ is not perfect, but it surely is way better than C in terms of safety.
Until a big OS vendor decides to push another systems programming language, we won't see any major adoption from the alternatives.
RAII has been with C++ almost from the beginning.
MFC's greatest benefit was that it made returning to plain win32 C programming without MFC a pleasurable experience.
Microsoft team made a prototype OO framework even more OO that what OWL and others offered. MFC was the result from the feedback over the said framework.
I'm also not convinced that Rust or Go are better or saner.
Maybe Rust will offer such stability in the future. But that's of no use to people and organizations who need to develop software today, and who need to be able to trust that the code they write now will compile and work tomorrow, a month from now, a year from now, and perhaps even decades from now.
C++ does offer stable, standardized, well-supported versions of the language. C++ does offer stable, standardized, well-supported standard libraries. There are numerous high-quality free and commercial C++ implementations available, for just about every platform imaginable. It provides a robust and predictable platform that serious and massive software systems can be built upon.
The theoretical benefits that Rust may bring are pretty much irrelevant as long as it isn't a production-ready language in the way that C++ is.
Not that I am disagreeing with your points, I am not. However, when people talk about C++'s problems, I immediately assume they talk about C++'s problems as a language rather than it's ecosysem.
Rust isn't out there to tackle C++'s ecosystem, tooling, legacy code or professional workforce, but rather Rust aims somewhere near C++ and fixes many of the language flaws which are inherent in C and C++, while still being competitive in performance and low-level control.
Rust is a pretty cool language, but I can't help being reminded about another very well-designed but ultimately unsuccessful C++ challenger, D. The parallels are really hard to ignore.
D, like Rust, had great syntax and was a breath of fresh air after coding with C++98. Neither Rust not D has a sponsor with really deep pockets to encourage adoption. Neither came out of a standards process. Both have had compiler and standard library issues. The big difference between the two at this point seems to be momentum and where the two are in their parabolic trajectories.
Also, Mozilla has much deeper pockets than Digital Mars.
Still I agree with you that it is very likely that Rust will follow a parabolic trajectory. The advantages as perceived by the industry compared with C++11/14 will be too few. At the same time it does not have the ecosystem.
Go succeeded because of Google's deep pockets and, perhaps more importantly, because it filled a large niche that even the authors did not anticipate: a faster language for Python and Ruby aficionados.
The problem is how to move OS vendors away from C's influence.
Rust is memory- and type-safe (as in: the compiler will not let you write a dangling reference, invalidate an iterator, or write exception-unsafe code without opting into an unsafe dialect). The security benefits alone of that are enough to justify the language for our use cases, and, from what we've seen, for many others. Safe zero-cost abstractions are a niche to its own.
What you describe is very different from, say, how Sun pushed Java, or Microsoft pushed C#, or how Apple will likely push Swift, or how a huge portion of the entire software industry pushed C and C++.
Facebook's Hack language is probably a much better example than D is of a language that they're actively supporting. It's a creation of theirs, rather than just a creation of somebody else's that they find useful in some limited cases.
Try watching new projects pop up at Rust CI [0] for a few days. With the possible exception of Node (which is not even a PL), I've never seen a language ecosystem grow this vast, and I'm a PL afficionado.
I think in a year's time, the question of Rust's stability and ecosystem will be entirely moot. It's a tough wait meanwhile, but I'm still investing the time in learning Rust (and it's a significant investment).
When I last looked at it, probably 40% to 50% of the projects listed had builds that were in the "failing" or "error" statuses.
That indicates that one or more of at least a few things are happening:
1. The Rust language and its standard libraries are changing at a pace that results in previously-compiling code needing to be modified before it will compile again with a newer version of the language/implementation, perhaps a very short time after the code was initially written.
2. The Rust compiler or other tooling is crashing or failing in some way while compiling these projects.
3. The projects themselves aren't being maintained on an ongoing basis.
4. The projects themselves were never building properly in the first place.
5. The projects' developers are targeting different versions of Rust (which probably means there will be interoperability problems for anyone trying to use them in a larger projects, especially when it comes to libraries).
And while there may be a lot of these projects, I've never found the quality to be very good. Many of them are extremely limited or incomplete. Many of them are little more than casual experimentation. Many of them are only developed by a single person, who often has appeared to have lost interest.
Those factors are disconcerting, especially for somebody who wants to use Rust for serious product development. It does no good if there are hundreds of libraries available for use, but half of them don't even build, and the ones that do are very incomplete.
Yes, I completely agree, and this is an entirely normal part of the language ecosystem development cycle. Rust is at the tail end of the experimentation stage, and as it converges on 1.0, more people will undertake serious projects.
I'm not at all worried about the quality of Rust projects. I'm just happy to see so much enthusiasm. I have no doubt that all this enthusiasm will transfer into some powerful libraries as Rust continues to stabilize and reaches 1.0.
But yes, it's still to early to use Rust for production unless you're willing and able to write your own libraries.
Then again, the "batteries included" approach of Rust's standard library leaves not much to be desired outside of domain-specific libraries.
People complain about the GC being available to use while simultaneously complaining that to avoid it you have to manage your memory yourself. You can't have it both ways. There is no memory allocation strategy that works best in every situation. Sometimes ref counting is best, sometimes stack allocation, sometimes RAII, sometimes memory pools, sometimes its the GC.
Rust has done some cool work with memory but even it doesn't free the programmer from having to consider and choose which memory allocation/ownership option is going to deliver the best performance on a case-by-case basis.
You're right about Rust and Go having much deeper pockets. D isn't backed by any corporation. It's 100% a community project. Maybe it won't ever gain a significant market share because of this. I don't know.
What are the compiler/standard library issues with Rust? Sure, it's taken time to get to a high level of quality, but no language compiler and library is going to spring out of thin air fully complete. In particular, I'm confident that the Rust compiler is of high quality for its age, especially in the quality of the generated code.
I'd like to concur. I've used the Rust 0.10 compiler and the only bug I encountered was that generating debug binaries was somehow broken. Apart from that, it was one of the smoothest experiences ever and the error messages are amazing.
In the C world this is extremely arduous since need to bubble the allocation-failure down through every level of code, adding cleanup to just about every function call. If you're using C++ and RAII you can just catch std::exception in one place to cover a huge number of places that an allocation can fail.
In modern systems I'm familiar with, malloc only reports failure on bogus inputs like -1, or address space exhaustion. Your process is likely to be killed before exhausting your address space (think iOS OOM handling, or Linux overcommit), especially on 64 bit. So checking for allocation success just isn't that useful any more.
The first is process limits.
The second is exhausting kernel data structure space for things like page mappings. I've seen this recently in AIX when allocating lots of memory that alternates mprotect permissions.
Even in the absence of the OOM killer (i.e. the old days) you had to do this -- otherwise the machine might be swapping itself unresponsive for ages before you ever get malloc()==NULL
Gotta love putting forth every effort in software to keep the BOM down :)
Are you talking about enabling exceptions, or throwing them?
I don't think it's very popular today. Modern implementation don't use this anymore and do not incur run-time overhead when no exception are thrown. However, they do incur some space overhead: the implementation need to maintain pretty large tables to know what needs to be unwound (which destructors to call, in which order) when an exception is thrown. In most environment this space overhead shouldn't be a problem (PC, server). But for embedded development it may be a problem. And then disabling exception to save space brings back the issues with error checking (or the lack of it...).
For more details, search for C++ exception implementation and you should find all the info you need. Or look into G++ documentation for example, this topic is covered somewhere.
As for coding standards, I suggest a book by the same author plus the current chair of the standard committee: http://www.amazon.com/Coding-Standards-Rules-Guidelines-Prac.... Another commenter has suggested the Google C++ Coding Standards, but despite their popularity they do not conform very well to "Modern C++" as I understand it.
Many features of C++ are targeted at library authors. Even if a given project won't allow template metaprogramming, it probably uses vector, which certainly does. And for good reason.
In the Java world, a Java EE CRUD application is a LOT different than a Swing application that does the same thing. Likewise, a Python Django application is a completely different beast than a console application.
In C++ you can have such variations, plus all the other paradigms, including:
* C with classes (people programming in this style often still use C strings, do deletes and frees in destructors).
* C++ as the full-blown OOP language, with extensive multiple inheritance hierarchies.
* Nearly functional, STL-driven C++. In this code you see nearly no loops at all, <algorithm> is the control structure.
* Template-driven programming, with policy classes, dozens of specializations, only header files.
Etc. Java does not have the legacy to 'embed' another language. Java does not do multiple inheritance, avoiding heavy-inheritance-based projects, Java does not claim to be a semi-functional language (though Java 8 brings Java closer in that direction), and Java does not provide a turing-complete template language that is a world on its own.
any recommended reading?
As much as I try to find "my" general purpose language of choice, and forr all of my inertia in learning yet another programming language, I believe languages should have narrower scopes. And there should be more languages. Specialized for specific use-cases.
And, as a pythonista, the "you can do/use it in many different ways" just irks me.
This seems to be the curse of any powerful core language (Scala, Haskell, ...) - on the one hand they allow you to make all kinds of useful abstractions that you can't make with e.g. Java. On the other hand, their abstractions are so powerful that they create seemingly different languages.
One could apply the same rule as C++ - stick to a subset of the language/abstractions. However, if you look at e.g. Haskell, a large number of libraries now depend on a library such as lens [1], so often it's not that much of a choice.
Another consistent part of C++ is that it gives you absolute control over memory, both allocation and layout. It's really this control that makes C++ unbeatable in performance. The good VMs can JIT their languages to match CPU performance on small routines, but they can't match C++ when it comes to manipulating big, complicated data structures.
I hate to spoil your worldview, but modern C++ is very alive and well in the scientific computing communities. Disney Animation implemented a new renderer using it, and our next movie is currently being rendered using the new renderer, so I highly doubt it's on its way out in the these areas.
Pharao Inc. built pyramids in ancient Egypt. It cost many lives of slaves but it was cheap them. Nowadays we make big buildings without slaves.
And hey, don't knock the Pharaohs!
First off, it's been known for some time that the Pyramids were built by paid workers:
http://www.boston.com/news/world/middleeast/articles/2010/01...
(Literate too, since they left graffiti)
http://www.bbc.co.uk/history/ancient/egyptians/pyramid_build...
The conditions that migrant workers endure building World Cup facilities in Qatar seem to be worse than those endured by Egyptian construction workers:
http://www.theguardian.com/world/2014/may/14/qatar-admits-de...
That you aren't used to doing greenfield development doesn't mean others are likewise impaired.
I don't know, I've been writing C++ for about a decade and the code I write is "modern" as far as I can tell. I just started a new project. It is C++, it is "modern", and Rust and Go simply aren't options.
Rust is an infant and not yet ready for prime time, and Go simply wouldn't be considered by management. Not because they're ignorant, out of date curmudgeons, but because they want a larger pool of talent to draw upon and a language that is well known, well understood, and has decades of work invested around tooling. I can't say that I blame them.
Why does the "pool of talent" even matters?
There must be something else, like fear of the unknown, risk aversion, "nobody got fired for choosing IBM"…
In the cases the customer is not willing to pay, developers get asked to learn off work hours, if they want to stay on the project.
For ecosystems where there is a "one way to do it", then picking up a random project or library from github and using or changing it is easy, as it is understandable in the same way as my own code; for C++ it is, well, different.
And this is directly caused by the language - the technical details of the language significantly influence the code ecosystem that grows around it. Lisps are another example of this - because it's simple to define commonly used stuff yourself, it results in every project doing the same things differently, adding a serious cost in readability and maintenance for anyone that's not the original author.
For business applications? Sure.
For system programming?
Only if they get an OS vendor godfather that pushes the language into their SDK, like any other systems programming language that got widespread use.
It shows a distinct lack of understanding of why people still use C or C++ to raise languages/environments like Go as viable alternatives.
D is the one true C++ without pretending being a superset of C. Rust is more modern than C++ and better in programming in the large. But D is really for low level programming and a good target for code generation. For me it is a good replacement for C++ and Delphi. It is even a good fit for areas touched by Java and C# like desktop and scientific apps. But it is not there yet because of lack of serious tooling and lack of bytecode but for the second disadvantage you earn performance. Nimrod for example could address this (with D as a code generation target).
Malloc() and free() aren't exactly predictable. If you really want guarantees, you need to write your own custom allocator, and if you don't need those guarantees, garbage collection is probably enough for your purposes.
Basically, if you're using C++ without real manual management, with custom allocators, pools, and all, you probably didn't need C++ in the first place.
This is not to say that the underlying allocator is necessarily deterministic, but you're making a false dilemma here by putting it in opposition to making decisions about custom allocators and pool allocators. You can use RAII with custom allocators. You can use RAII with memory pools.
And that's where C++ really does shine. It's a niche that hasn't even really been attempted much, let alone that it's been surpassed in.
void main() @nogc { /* ... */ } // this program doesn't use the GC
Surely libraries in other languages have the same problem? They don't look anything like each other.
wxWidgets and Qt look nothing like each other but it isn't a problem at all. The signalling mechanism / event handling between the two just hides function pointers, so it isn't a headache. In fact, MFC looks like wxWidgets to me. Not sure what the problem is?
EDIT: Not sure why the downvote(s)? Do people get downvoted here because someone points something out that is true on a subject/language that they like/dislike? Or was it the tone or supposed tone that the person read the comment in? Please let me know!
- Do I use char* for strings? It sounds like wchar_t is 16 bits on some systems and 32 on others, so I should avoid it?
- If I want to read & write UTF-8 files, how do I turn the bytes into 32-bit wide Unicode strings?
- Are there special functions I should use for handling Unicode strings?
More generally, where do you go to discover C libraries you can use?
I am (was) reasonably proficient in C, but I haven't used it much for over ten years. I'm surprised how many things I just don't know how to do!
Sorry this is not a C++ question. I'd like to get back into that also, but I'm trying to work my way up from the basics. :-)
You really need a library when dealing with unicode, if you are doing anything advanced.
How do you split a sentence into words? Spaces, right? Oh, Chinese doesn't have spaces.
How about sentences? Paragraphs? Even characters are a pain to iterate over.
In C++ unicode is as simple as: string s = u8"This is always a utf8 string.";
[1]http://article.gmane.org/gmane.comp.version-control.git/5791...
For Unicode strings in C++, you can either limp along with the wchar_t support, or leverage something like ICU. Neither is especially easy.
Also, std::toupper inherits the system locale (or whatever you set it to), so if it is utf8 it would do proper utf uppercase conversions. You need to parse per character though, and that depends on the locale again.
Like it or not, C is the lingua franca of the programming world. Pretty much every other language out there provides C bindings, not C++ bindings. Which means that when your function exports something wonderful like smart pointers, my world just becomes painful.
Furthermore, in embedded environments, it can be challenging (to use a euphemism) to get source code debugging up and running. If your code is written in C, it's not so bad, non-optimised machine code generated from C tends to match the actual C code fairly closely, to the point that you can very nearly read it as easily as the original source. This is not true for C++, which means that every time something goes wrong in C++ code, I'm probably going to lose a week of my life inserting trace into the code, compiling, deploying to target, and running the test, ad infinitum. Not fun.
Even in the case where you're writing an application, I'm personally dubious about the benefits of C++. Write the application in a higher-level language, personally I like Javascript (JavaScriptCore) for this, but I've had good success with Ruby and lua as well. When you hit a performance bottleneck, push the performance sensitive code into C, and create bindings. As a bonus, your C code is now easily available to be used as a library from any other language, without inducing homicidal tendencies in the user.
}
Hey look, C API.
> This is not true for C++,
Depends on the code you write. If you write C in C++, you get the same near machine parity, since its the same source material. If you do not use namespaces you don't even get name mangling.
Most programmers will tell you to use UTF-8 for in-memory strings. But it's not easy to figure out if a particular char* is already encoded as UTF-8, and it's common for people to forget that Unicode characters can take up to 6 bytes in UTF-8. I know I'm in the minority, but I prefer to use UTF-16 or UTF-32, because nobody makes the kind of mistakes with UTF-16/UTF-32 that they make with UTF-8. Plus, you can't accidentally pass a UTF-16-encoded string to a non-Unicode-aware function.
Or did you mean UTF-8 encoded surrogate pairs?
The benefit with UTF-16 is that you can't accidentally pass a string to, say, strlen(). But, yes, people will forget that not all Unicode code points fit in 16 bits, and won't test with the right kind of input to find out that they've done it wrong. So errors can still creep in; but I will continue to argue that those errors are less common because the fact that you're dealing with Unicode (and not ASCII or something else) is more obvious and you're more likely to need library calls (that will do the right thing) to do anything useful.
I'm not sure why you'd prefer UTF-32, it doesn't make correct text manipulations any easier, but — much like UTF-16 — it does make incorrect assumptions and text manipulations much easier.
UTF-8 for strings on disk, yes. But UTF-8 for in-memory strings has a long track record of being much harder to actually do correctly.
UTF32 will not help you much with that, save that you've got a separate type for "strings" and "bunch of bytes"
Which you can have anyway, so do that, it's a good idea which doesn't require using UTF32.
> But UTF-8 for in-memory strings has a long track record of being much harder to actually do correctly.
As if other in-memory encodings had a better track record.
Yes, people forget to normalize their UTF-32, UTF-16 and UTF-8 strings before comparing for equality. Yes, people forget that whether a code point is a letter depends on who's asking the question (I usually don't consider Greek letter pi a letter, but Greeks do). Yes, it's true that reversing a Unicode string in any encoding requires more than simply reversing the individual elements (because of combining characters).
So, yes, it's possible to get things wrong in any encoding. But UTF-8 has more ways to screw up than the alternatives. And UTF-16 has a few more than UTF-32; but I can accept UTF-16 if there are external reasons to (e.g., working on Windows).
But you can still copy only parts of a grapheme cluster. If you want to do Unicode right, you have to treat even UTF-32 as a variable-length coding.
I realize I won't convince you. That's what I meant in the original comment that I know many people disagree with me on this.
Glib seems to.
https://developer.gnome.org/glib/2.37/glib-Strings.html
Though in complete fairness the type appears to be just a "bags of bytes" type and so could hold anything, it's really meant to hold UTF-8 (as you can tell from the functions that append/prepend Unicode chars).
Which is relevant… how?
> Can you point me to any projects that manipulate UTF-8 encoded in-memory strings and actually use a different type for it them?
Rust does. Python 3.3 does something similar but slightly different (it switches internal representation between iso-8859-1, UCS2 and UCS4 depending on the string's codepoints).
> I realize I won't convince you. That's what I meant in the original comment that I know many people disagree with me on this.
Of course you won't convince me, your original comment is based on inane premises.
Note to put aside, since this was all about C++, the toupper() in <locale> is a template type that takes an arbitrary character type and a locale. There are also functions for locale sensitive collation and comparison. So, modulo bad implementation, you should be able to do basic unicode string handling in ISO C++.
The GNU stdlibc++ manual goes in to quite a lot of detail:
https://gcc.gnu.org/onlinedocs/libstdc++/manual/localization...
The locale stuff has been intentionally left vague. So:
(1) assuming that your implementation supports passing a char16_t or char32_t to the functions in <locale>, you're guaranteed it will do the right thing as far as Unicode and the C++ standard (although, there are some well-known problems with what the C++ standard defines the "right thing" top be for lowercasing epsilon -- since in Greek, there are two lowercase forms of epsilon, and the C++ standard doesn't provide the function enough information to decide between those two forms -- and for uppercasing ẞ (LATIN CAPITAL LETTER SHARP S) -- because in German the uppercase form takes two letters, and the C++ standard assumes doesn't allow for that).
The fun part is that plain char's can be encoded in several different ways, and not all have anything to do with Unicode. So you need to have a Unicode-aware locale for the functions in <locale> to do anything sensible with Unicode. Of course, that's something of a tautology, but I'm not sure what the standard requires for locales. So, yes, if your implementation is Unicode aware, you can call a standard C++ function to get what you want, but be sure to call the right one. There's another, with the same name, that isn't guaranteed to do what you want.
A language where the "String" data type is as follows:
A rope of "logical characters" (One or more code points, such that they are logically one character. So an accent is combined with the previous character, that sort of thing.)
With the additional "restriction" (read: implementation detail) that within a single node all logical characters must have the same width. (You can, for example, store a single one-byte character in a run of two-byte characters as an overlong-encoded two-byte character, but this is just an optimization.)
Short ropes degenerate to a flat array.
(You have to do a workaround for single code points that encode multiple logical characters. You split them into N parts encoded in the private unicode range or something similar, and when displaying them recombine them if they are in the correct order, otherwise normalize them. Although I'm up in the air about this. Should reverse("st") be "st"? Or "ts"? (That's the single unicode character "st", for those that are confused.))
Ideally, you put character encoding directly within nodes.
That way most things "just work". Running a string through the encoder twice doesn't do anything, as it detects the encoding is the same as the target encoding and doesn't do anything. Reversing a string "just works". Indexing a string is sub-linear time, but gives decent results. (Indexing a string and getting invalid unicode as a result is never fun!) Concatenating strings takes sublinear time even. This works really well with immutable data structures, or quasi-immutable data structures. (there's some tricks with rewriting ropes to take maximal advantage of structure-sharing that preserve the illusion of an immutable data structure without actually being immutable.)
And if you really want you can start doing fancy things like allowing lazy generators within strings, or lazily decompressing / reading data from disk.
To store on disk? Yeah, go with UTF-8. (Or my personal favorite pet encoding: compressed UTF-32.)
For instance, even within the 16-bit Basic Multilingual Plane, it is not safe to reverse a UTF-16 string by simply reversing each block of 2 bytes, as a Unicode glyph (e.g. á) can be composed of a pre-combined code point which only takes 16-bits, or a base character (a) followed by a combiner (´).
The pre-combined variant would reverse just fine, but the renderer-combined á would reverse to ´a, which is probably not what was intended.
If you're dealing with Unicode you need to be dealing with a good library and you need to be understanding what you're doing, once you go away from simply reading/displaying/serializing bags-o-bits.
But if the latter is all you're doing, UTF-8 is just fine, and less susceptible to mistakes with code that works correctly on C strings.
The upcoming version has it.
> - Do I use char* for strings? It sounds like wchar_t is 16 bits on some systems and 32 on others, so I should avoid it?
In general you should use std::string and UTF-8, since UTF-8 is a relatively safe encoding for sub-string search and replace, and (locale insensitive) lexical comparison/ordering. Windows uses a 16 bit wchar_t (UTF-16). Mostly everyone else uses 32 bit (UTF-32)
> - If I want to read & write UTF-8 files, how do I turn the bytes into 32-bit wide Unicode strings?
http://en.cppreference.com/w/cpp/locale/wstring_convert
> - Are there special functions I should use for handling Unicode strings?
Nope. You need a library for that. Manipulating natural language is a tricky business anyway, beyond single mortals, and you will likely get it wrong.
https://github.com/cplusplus/draft
The current version is a slender 1365 pages, including the standard library.
Is it lambdas? been around for literally decades. Is it type deduction? again been around for quite some time, far better type inference has been available in the likes of Haskell for quite some time. Is it addition of a particular threading model to the standard? this has always been available via some form of library, it just know means the language is truly obsolete if the model changes. Allow GC'd implementations? again decades.
What is modern about any of features that have been added?
Not writing modern C++ means:
- writing C++ as if it was plain C
- doing OO programming with big object graphs
- manual memory management
- not using the standard containers and algorithms
- writing functor objects
Ever heard of weak_ptr?
Modula-3 generics are good enough to even implement reference counting data structures.
The going VM craziness of the last two decades pushed such languages away from the mainstream and thus younger generations get surprised by such approaches.
Nothing. On the other hand, which features of a “modern” language are missing in C++ by now? Type deduction is still a bit less powerful than in Haskell, yes, but apart from that I can’t really think of anything that may or may not be missing.
This in turn implies that C++ allows essentially any style of coding you may wish for at the moment while at the same time staying some orders of magnitude faster than essentially the entire competition.
The real wins in performance for real world applications are in terms of algorithmic complexity. A poorly implemented solution in C++ will still be slow, the language does not make it fast.
Any micro optimization you can make with C++ will be an order magnitude less significant than O(log n) vs O(n).
The likes of Janestreet will likely need high performance software yet have great success with Ocaml for example, which incidentally can be very fast.
Just saying C++ is fast does not make programs written in C++ actually fast.
Yet a well written implementation in C++ will still be faster than an equally well-written implementation in, say, Python or Haskell or whatever. Not in an asymptotic sense, but easily by a factor ranging between two and 200. For me, this can be the difference between waiting a couple of weeks or half a year for some computation to complete :)
> Just saying C++ is fast does not make programs written in C++ actually fast.
Of course not, but C++ makes it possible for programs written in C++ to be fast.
But if in your problem area you can get a competitive advantage by being faster, using less memory, or tightly controlling other resources, then C++ is probably the right choice. If you really need it, you can use some inline assembly too.
For example, look at a VM's JIT compiler: it needs to capture a profile from a running application, analyze hotspots in that profile, recompile those on the fly to native code, and coordinate with the VM to swap that out on the fly. The more time and memory that is used to do all this, the slower every application on the VM will run. Since there's a very constrained environment, C++ is a good choice for JIT compilers.
And if you look at the CLR/VES or JVM, they are indeed written in C++.
On the other hand, there is a reason why native apps are popular on the iPhone. Likewise, some games are programmed in high-level languages, but the performance advantage of C++ keeps it dominant in games. Between games and mobile devices, I'd say C++ isn't going anywhere any time soon.
C++ can indeed be very bloated, like you say. On the other hand templates do allow for code reuse without the function call overhead.. I believe std::sort is faster than qsort. For me, if there was another language that was as well supported as C++ but allowed higher-level structures and programming methods, I'd be very much in favor of it. For now it looks like new versions of C++ are the closest there is. Nobody really likes C++ for its elegance, it's just a very practical choice.
When you read a language shootout, a lot of times a factor of 2-2.5 times slower than C or C++ is considered to be "good enough". If you get your Clojure code that fast, everyone calls it a day. For me, a typical run of my experiments took about 3 weeks on (I think) a Core 2 Quad using all four cores. So in the best optimized Java I could find, that would have been about 5 extra weeks spent waiting around for results, and I had several cycles like that. All told, I imagine it would have added a year to my work.
I'm not necessarily picking on you here. You did say "rarely", not "never". But I don't think a lot of people are aware of how common it is for a factor of two to be a complete deal-breaker.
See this: http://lemire.me/blog/archives/2012/07/23/is-cc-worth-it/ Particularly the comments section contains various results obtained from different compilers / versions. Variablility is higher than 2x for GCC.
Comparing with Clojure is not fair, because it is not really statically typed, and known to be much harder to optimize for speed than e.g. pure old Java.
The link is fine, but only shows micro-benchmarks. It's much easier to get a 3x difference in execution speed between compiler versions when you have a three-line example -- you're maybe exercising 5% of the optimizer?
The current version of the C++ I was using comes in at around 50kloc. The Java and C# versions were a bit smaller, since once I stopped testing the platforms, all the new code only went into the C++ version, but it's a significant piece of work. I haven't seen any significant real application for which the theoretical benefits of Java (JIT's profile-guided optimizations, etc.) have really come to pass. You can write slow C++ code, but if you know what you're doing and instrument carefully, there's very little or no evidence that Java can be as fast on real programs.
Those three lines can be as well a bottleneck in a big program, responsible for 80% of its runtime. This example was to show that compiler-induced performance differences in a single language can be just as large (here: up to 4x) as differences between Java and C++ in microbenchmarks. Therefore 2x difference in a microbenchmark where Java is losing to C++ is probably not a statistically significant difference, even though it may be important to the end user. If you rerun this benchmark in 3 years from now, using newer versions, you might as well get completely different results.
As for real applications - that you don't know of any real, fast Java program, doesn't mean there exist no evidence. Sure, it is quite hard to find a pair of two programs doing exactly the same written in two different languages, but there do exist quite a few high-performance Java apps out there which are #1 in their class: Netty, Apache Cassandra, Apache Spark, LMAX disruptor (Java used for ultra low-latency app, see: http://programmers.stackexchange.com/questions/222193/why-di...). Someone also ported Quake2 to Java (Jake2) just to show it was possible, and that didn't make it slower.
When your main problem is IO, thread contention, etc., Java gives you better tools to address those problems. It's just not at all well suited for the kind of client apps that people run on their desktop computers, and to a lesser (but still visible) degree, it's not well suited for CPU-bound things like a lot of scientific computing, which is more where my expertise lies.
Looking at Jake2, the author notes: "The 0.9.2 release shows a big improvent due to the new “fastjogl” OpenGL renderer. The new renderer reduces the number of native interface calls. JNI calls produce a considerable overhead and were the main bottleneck in our application." If he's doing enough JNI to make this the main bottleneck, then clearly quite a lot of the heavy lifting isn't being done with Java.
Is it possible to write programs in other languages that are just as fast as good C++ implementations? Often it is not.
That performance comes at a cost, it really depends on what your application is. Horses for courses.
Wrong. See (from about 46min): http://channel9.msdn.com/Events/Build/2014/2-661
I’m not sure about threads (and how light/heavy those currently in C++11 are).
[0] https://stackoverflow.com/questions/34125/which-if-any-c-com...
* Hygienic macro system. * Pattern matching. * Strong generic type system. * Persistent containers. * Lockless data structures. * Memory-safety. * Null-safety. * Reflection. * Dynamic/variant types. * Modules. * ...
Comparing a later version of language to an earlier one to measure modernism seems rather pointless.
C++ is a production ready systems language, not a theoretical CS research paper. How do you propose we define modern in this context then? As I'm sure you're aware, it takes years to vet design features, debate whether they can be implemented, whether they affect performance, whether they have unintended side-effects, whether they break existing code, etc. 'Modern' concepts are already old by then. Also, sometimes features can't be added to a language because of practical real-world issues that have nothing to do with the language itself. (e.g. longer compile times).
I don't see anything particularly wrong with calling a language modern as it adopts features. Certainly, I would agree that one should not then claim the language to be modern in the sense of cutting edge research.
Lambdas have been understood for many many years, the same goes for GC. The were not only in the domain of academia.
Common Lisp has many of these features and more, being a multi-paradigm programming language. And has been used in industry for many many years. Yet people say CL is antiquated while it has so called 'modern' features.
Close to none of course, but that isn't the point AFAIK.
The point is all of them have now been added, hence the 'modern' connotation, and another part of the point is that C++ now even more is a language rather flawlessly combining all those paradigms.
I'd like to see whats new with 14.
Edit: http://en.wikipedia.org/wiki/C%2B%2B14#New_language_features
Until then (and even after), Stroustrup's The C++ Programming Language (4th edition) is the canonical resource. It's a reference but is also intended to be read.
http://shop.oreilly.com/product/0636920033707.do
I'm reading the PDF and it's quite good.
Not fair to judge the language by the fools that used it 15+ years ago, but I have no use for operator overloading, copy memory leaks and all the other C++ obfuscation.
C++ would probably benefit from a "lessons learned" do-over with a new name (as referenced elsewhere in the Perl 6 / Python 3 debacles)
C++ is a language designed by committee. C++14 is meant as a "tock" release, fixing some of the things in the C++11 "tick" release. ("tick" releases are larger, and "tock releases fix some of the problems in the "tick" release).
Compilers then attempt to implement the standard, and have their own versioning system.
Note: C++03 was a very minor change (sort of a "bug fix"), so people sometime refer to C++11 as direct successor of C++98. Also in the interim (2007) there was C++-TR1 ("ISO/IEC TR 19768:2007") which was not a formal standard per se, but instead a technical report specifying bunch of standard library extensions (which were formally included in C++11)
For sake of completeness: The format C++YY is the one which is commonly used almost everywhere, but the official language name follow ISO's convention. Here is a mapping:
C++98: "ISO/IEC 14882:1998 Programming languages C++"
C++03: "ISO/IEC 14882:2003 Programming languages C++"
C++11: "ISO/IEC 14882:2011 Programming Language C++"
C++14: "ISO/IEC 14882:2014 Programming Language C++"
There are also language classifier like (E), (F), etc present at the end (e.g., "ISO/IEC 14882:2014(E) Programming Language C++"). I am not sure if the official standard is fixed in a particular language, or are all the different language translations equally authoritative (I suspect the latter, but it's just a guess).
Now of course it's C++11, which does have some nice features, but really I think we've reached the point where we need to start again (downvote away).
Let me give you an example: I recently came across some code that was written years ago that has two size types: one 32/64 bit signed and the other 32 bit unsigned. This creates a bunch of issues when compiled on 32 and 64 bit architectures and there is a substantial amount of effort to clean it up.
I point out things like this to colleagues who are very pro-C++ and I inevitably get the same response: "well that's just bad API design".
Thing is, if you look at the history of this example it's a series of incremental changes, all well-meaning and reasoned, some of which are done by people who I could only call luminaries, and even they make significant and far-reaching mistakes.
So what hope do the rest of us have?
But my biggest problem with the C-dialects is pointers. Namely if you return or receive a pointer, it's not necessarily clear who owns it. The way this is handled is comments like "DO NOT delete this" or "you MUST delete this".
I like that a language like Rust is trying to formalize the concept of object ownership. I'd really like to see that idea mature and take hold.
Until now there hasn't really been a competitive alternative to C/C++. It's not Go (as much I love Go). Maybe it's Rust. We can but hope.
My other big problem (and this applies to Java too) is directly dealing with low-level multithreading primitives like threads, thread groups and mutexes. I really like that Go has taken a different approach here.
What I find with particularly young programmers is they don't have the appropriate fear of writing multithreaded code. It's really, really hard to write correct multithreaded code with low-level primitives. It's why (excellent) books like Java Concurrency in Practice exist.
As for the feature list of C++14 [1], I wonder what all these "auto" declarations will do to the significant work required for static analysis tools, that are an essential part of modern, large-scale C++ codebases.
The literal types (like "s" for std::string or seconds) are cute but at some point the STL was optional. I'm a little leery of embedding it directly in the language but hey I'm no expert.
Like a lot of things with C, you need to handle ownership by convention. I generally try to make the actor that created the heap pointer the owner of it and responsible for its destruction - i.e. instead of allocating buffers and handing them back up the chain full of data, pass them down from the requester where possible. If the length is not known at that point, create another routine to calculate it. Using techniques like this, ownership can become easier.
You can do anything with it, but that's half the problem!
And personally I like threads :)
QString operator""_qs(const char* c_str, size_t len)
{
return c_str;
}
void foo()
{
auto iama_non_stl_type_ama = "foo"_qs;
}Such things happen whenever an invalid assumption that is commonly true becomes not so commonly true, such as the 32-bit to 64-bit migration. That said, C/C++ provides you the tools: size_t is an unsigned type meant for storing array indexes and the size of objects in memory. If you want a real integer, then (unsigned) int. If you need integers of a definite fixed size, u?int(8|16|32|64)_t. Granted, I've encountered that not enough people take the time to understand the tool they're using. Honestly, I wish the default integer type was not fixed size, and especially not platform dependent fixed size, like Python; for non-[indexes/sizes], I feel like this is usually what you want.
> "well that's just bad API design".
Well…
> But my biggest problem with the C-dialects is pointers. Namely if you return or receive a pointer, it's not necessarily clear who owns it. The way this is handled is comments like "DO NOT delete this" or "you MUST delete this".
This is true; in C++, your use of pointers should be minimal, though this can be a problem with references just as easily. In the (special) case of std::shared_ptr, ownership is clear. That said, this is a problem not unique to C++: it exists in Java, Javascript, Python, and many others as well. For example,
some_list = [1, 2, 3]
some_obj = MyObject(some_list)
If some_obj expects to own that list, and it's constructor is: def __init__(self, some_list):
self._some_list = some_list
which I see a lot, you've got the same problem. (I'm also interested to see how well Rust tackles this, as I agree it's a problem.)> My other big problem (and this applies to Java too) is directly dealing with low-level multithreading primitives like threads, thread groups and mutexes. I really like that Go has taken a different approach here.
Honestly, I've never thought multithreading was "hard". There's a set of rules you have to hold yourself too, otherwise, yes, you can make your life very hard. If you limit shared data as much as possible, and what data is shared has a well defined locking order (preferably behind code that enforces it) — often this is just a single mutex — then I don't see the problem. Thread-safe queues ("channels", I think Go calls them) are also useful to establish "service" like threads.
Is this a "see how well it actually works" or a "I don't know how this works and I'm interested?"
I'm curious because this is possibly Rust's most important, interesting feature, and I want to make sure we've got some reasonable messaging here.
If you are ever using bare pointers instead of `unique_ptr` you are probably doing it wrong.
For more: http://herbsutter.com/2013/05/29/gotw-89-solution-smart-poin...
The problems are even worse than with manual memory management, since there you often get away with RAII. Say a function call is returning some sort of list, or some other data structure. Was the producer operating on another thread? Was that data structure signaled to other consumers as well? Can you modify it without locking?
To make matters worse, locking is extremely inefficient, it limits the possible parallelism, throughput and vertical scalability and suddenly you start thinking of not protecting reads, since shared reads should be parallelizable, right? And so you need to look at alternative means of synchronization and then suddenly you end up reasoning about happens-before relationship arising from usage of memory fences, non-blocking algorithms and single producer / multiple consumers scenarios. And then you discover that C++ doesn't have a strong memory model to speak about and that at least before C++11 it was all platform dependent.
Of course, I like this state of things, since my favorite platform (not C++) has a better memory model and plenty of higher level abstractions built on top, like actors, CSP, ring buffers, futures, Rx, iteratees, immutable data-structures, etc... but yeah, people able to reason about concurrency are also avoiding it like the plague.
Raw pointers are only views of the object passed around, these confer no ownership.
std::unique_ptr owns a single unique instance of the memory.
std::shared_ptr (and std::weak_ptr) confer ownership of the memory amongst several other entities.
I'm trying to make a C++ game with fat libraries like Ogre3D and bullet3D, often on a laptop, and that would really be fantastic to not wait 10s or more each time I edit a header.
I've seen a presentation, basically modules would decrease compile time from M x N to M + N.
It's annoying, it's a drag on productivity, but in the long run it's arguably necessary.
Some other languages which reduce verbosity by making more things implicit make it harder to understand what's actually going on behind the scenes. You lose a lot of information.
Whoa, no it doesn't. C++ is far more verbose than necessary for things like creating algebraic datatypes or really creating any types.
std::vector<int>::iterator it;
for (it=arr.begin(); it!=arr.end(); it++) {
...
}
as an improvement over for (int i=0; i<len; i++) {
...
}
Not entirely unrelated: I'm currently busy verbosifying a large chunk of C++11 code into C++90 code because Reasons (or so the maintainers assure me). template <class T>
void foo(T arr)
{
for (auto it = arr.begin(); it != arr.end(); ++it)
{
std::cout << *it << std::endl;
}
}
You could pass a `std::map<int>` to `foo`, or a `std::list<string>`, or a `std::vector<char>`. You could even create your own classes and give them to `foo`, as long as they implement the `begin`/`end` protocol.It's certainly more verbose than necessary, but it can be convenient.
Ideally, it should be something like:
for (auto it : arr) {
// do something with *it
}The advantage of iterators is that they're incredibly flexible. You can use them for sub-ranges, reversed ranges, non-ranges like input and output iterators, etc, etc. This is vastly more powerful than something like, say, Objective C's NSFastEnumeration, which just allows for the trivial case handled by the range-based for-loop.
Because there are algorithms where you may not want to walk through the whole collection. STL wasn't meant to be a container library alone, it also includes many generic algorithms that work using iterators to delimit the range of data to be operated upon.
std::vector<int> myVec;
for( auto it = myVec.begin(); it != myVec.end(); ++it );
or if you prefer the external begin/end syntax: for( auto it = std::begin(myVec); it != std::end(myVec); ++it );
or the most succinct (replace && by & if writing): for( auto && item : myVec ); for(auto& item : vec)
syntax was merely a talking point being tossed around C++0x meetings. And to this day the project I'm working on still hasn't officially dropped support for C++90 so I'm stuck with the old syntax anyway :/That is strictly not necessary. `auto&&` is what is now being called a universal reference: `item` resolves to `const int&` if `myVec` is const, and to `int&` if `myVec` is mutable. `auto&&` does the right thing in the majority of cases. In fact, the following extension [1] has been proposed for C++17 (and already implemented in recent clang builds):
for( item : myVec ) { /* do stuff */ }
which is meant to be a short-hand for for( auto&& item : myVec ) { /* do stuff */ }
[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n399...Times have changed now of course.
Just to write a class in C++ with a constructor and destructor which are not inlined, you have to repeat the class name about seven times: three times in the class declaration. Then four more times in the definitions of those two functions:
class verbose {
public:
verbose();
~verbose();
};
verbose::verbose()
{
}
verbose::~verbose()
{
}Also in the "hiding stuff behind the scenes" department C++ is quite bad.
SomeClass someMethod(SomeClass a, SomeClass b) {
...
}
is doing a lot behind the scenes. Code below is better but it's longer and less convenient to write. const SomeClass& someMethod(const SomeClass& a, const SomeClass& b) {
...
}
And actually C++ code isn't easy to reason about wihtout reading the whole program. It isn't even easy to parse.What's going to happen when you run this?
y = f(x);
It may be that f is function, or a type. f may return the correct type to assign to y, or it may return something else and automatically run some conversion. There may be copy constructor and some destructors involved if it's returning object and not reference. It may run overloaded operator= and do anything at all, for example add f(x) to y. Hell, f can also be a class with operator() overloaded, and you would need to track its state to see what will happen.And we haven't even touched the subject of #define.
It's much easier to reason about Java code for example.
The reason the previous commenter asked if you're from the java world is because in many highly important areas, the effect on memory and speed this would cause would be unacceptable. These areas _tend_ to be left to people who understand languages like c, though, so a lot of newer languages make decisions ignoring these good use cases.
Also I don't think it's that big of an achievement to understand C. Despite its flaws it's very simple language, very different from C++.
To the point - you could ensure that compiler can de-virtualize your usage of structure (or class if you will) by adding "nonvirtual" to every method it implements or derives. I don't see how it's any better than having to delete "virtual" from every method it implements or derives. Just a question of defaults, and I'd say most of modern C++ code isn't written with the performance goals that justify nonvirtual as default. You can and should profile after writing something anyway if you care about performance.
And anyway if you have derived classes it's almost always the case that you want at least some of your methods virtual, otherways what's the point?
In practice, most classes are designed without inheritance in mind and yet, being able to extend and override them has proven infinitely more valuable than the occasional case where such an overriding breaks the parent class.
The practical reality is that even if a class is not designed for inheritance, inheriting from it is unlikely to break it but very likely to make its user's life much, much easier.
tl;dr: Just because it's "infinitely more valuable" in Java doesn't mean the same for C++.
Think it in this way. Many respectable people has been making a case to avoid inheritance[1][2]. What you are proposing would actually be an incentive to them. I don't know about you but the amount of functions that I actually override in my code is not even close to the 20%.
Why should we set a default for that 20%?
[1] http://channel9.msdn.com/Events/GoingNative/2013/Inheritance... [2] http://www.gotw.ca/publications/mill07.htm
And you do want to refactor your virtual methods and then extracted methods do usually need to be virtual, even if at first they don't they may need to become virtual in future, and IMHO it's better to just make them virtual from the start, if you don't REALLY need the performance.
You can mess up because of nonvirtual-by-default too, especially in C++ because of the difference between stack and heap objects.
struct A {
virtual int f(int x, int y) { return g(x,y); }
int g(int x, int y) { return x+y; }
};
struct B : public A {
int f(int x, int y) { return g(x,y)+1; }
int g(int x, int y) { return x+y-1; }
};
B* b1 = new B();
A* b2 = b;
B b3;
b1->f(2,2); // 4
b2->f(2,2); // 5
b3.f(2,2); // 4
This bite me a few times in C++.The override keyword was added in C++11 to help prevent the sort of mistake you were trying to show. Any methods you mark with it will result in a compile error if they are not actually overriding anything.
For example, if B::g were marked as override, it would fail to compile because A::g is not virtual.
Unfortunately, class inheritance is the only way to create the equivalent of an interface or (Scala-type) trait in C++. So, even if you avoid class inheritance in general (which is a good thing IMO), you still end up doing inheritance if you want run-time polymorphism in the form of abstract classes or abstract base classes.
I am using C++ right now for embedded code but otherwise I write mostly Javascript. There was a time when C++ was the standard choice of language for desktop apps etc., but that's hardly the case any more. You choose C++ if you need performance and control. And I think the "default means the least overhead" concept makes a lot of sense there.
Also, inheritance is a very central part of mostly all Java code whereas it's much less idiomatic (modern) C++. In C++, classes serve to give you RAII and you specialize with templates.
Zero-overhead abstraction is a key talking point of the language. Virtual-by-default would contradict this entirely.
These days, the economy of a vtable pointer is not really a good reason, and all languages that have the opposite default (such as Java, as you point out) are doing quite fine.
Because of this default, I can't count the number of times where I've seen "#define private public" and other horrors that developers used to be able to extend classes that their creators were too short sighted to design properly.
If anything, the performance difference between std::vector<shared_ptr<Foo>> and std::vector<Foo> is even greater today than it was twenty years ago.
Not being able to inline a method like (from vector)
T& operator[](size_t pos)
{ return data[pos]; }
Would kill performance.In languages which do run-time optimisation you can inline such methods later, but in C++ that's not possible and proving when you can de-virtualise a method (which most compilers do) is very hard and often fails.
The first form of 'someMethod' will also accept all 4 combinations of moves and copy operations on 'SomeClass': (copy a, copy b), (copy a, move b), (move a, copy b), (move a, move b). Your second, less convenient, function results in moves degrading to copies, leaving performance on the table if 'someMethod' performs mutation.
Your 'y = f(x)' ambiguity isn't a problem in practice, since most code styles use different naming conventions for classes/structs and function names.
Conversions, construction, copy, move, and assignment semantics etc, are one of the most important, and one of the most difficult things to get right, when it comes to class design. If you make sane choices though, and put thought in to it, automatic conversions etc shouldn't be bothersome.
I don't have a link - it was in some recent conference. He stated that every time he added a new feature everyone would be up in arms and demand a really verbose implementation, which he added reluctantly. Now that everyone is used to the features they complain about how ridiculously verbose it all is.
There isn't any reason for the craziness of
template<typename T>
void foo(T a)
vs void foo(auto a)
Certainly things can become too implicit, but C++'s heritage of verboseness is due to the conservatism of the standards committee, not because anything less would be confusing. template<typename T>
void foo(T a, T b)
vs void foo(auto a, auto b) template<typename T, typename U>
void foo(T a, U b)
:)C++'s type system is actually pretty strong, but the amount of boilerplate that is needed to create a new type means that it is very difficult to program in a type safe way... without being incredibly verbose. Creating a type safe "Length" type is too much of a pain in the ass for anyone to actually do it.
Which is what I mean by "too verbose". It is so verbose that instead of securing the "specific and obvious" in strong compiler guarantees, we fake it with implicit conversions and typedefs.
The problem with OpenGL was that they tried to retrofit an API that assumed a certain underlying hardware model to modern (i.e. less than 15 year old) GPUs. It was impossible to do in any sane manner.
But then I presume the parent was sarcasm.
I think the parent's comment is just plain ignorant. Saying stuff that he thinks is "cool" because he doesn't know better.