I love C++11 and use it every day, but I think putting references in the language was an 'original sin'. They should have stuck with C's model: it's either a value or a pointer to a value. References just added a pile of complexity and pontificating about whether something was being copied, moved, or passed by reference.
That means that Stroustrup couldn't have ditched pointers, but if he wanted to implement operator overloading for value types with same efficiency as C he needed some way to support doing that without using pointers directly: http://www.stroustrup.com/bs_faq2.html#pointers-and-referenc... http://stackoverflow.com/questions/8007832/could-operator-ov...
A lot of the nastiness of C++ comes from trying to maintain C compatibility: Special behavior for POD, most vexing parse, .h/.cc file split, everything preprocessor and many other misfeatures. Of course, there's also the flip side of it: if C++ wasn't a near-superset of C, it would have never become so popular.
const string& s = max<string>("a", "b");
cout << s;
Standard types and functions, const references, no warnings, everything by the book. But it crashes.There's a similar can of worms related to slicing (treating Derived* as Base* is silently unsafe because arrays and copy constructors exist). C++ is scary.
1) Replace max("a", "b") with max("b", "a"). Run it, look closely at the result, and be enlightened.
2) Replace max("a", "b") with max<string>("a", "b"). Run it, look at the result, and be enlightened in a different way.
As a small hint, your code invokes unspecified behavior, while my code invokes undefined behavior.
If this exercise doesn't put the fear of C++ into you, then I don't know what will :-)
EDIT: Not sure if this is it, but after some digging I've found [0] on lifetimes of temporaries. As for the lacking template argument, presumably const char* is inferred and a temporary string is constructed in main?
As for max<string>("a", "b"), it implicitly converts both arguments into temporary strings, then returns a const reference to one of them. Since it's a reference to a temporary, it becomes dangling when max returns, but you can assign it to a const string& anyway. When you try to access it, you'll get garbage or crash.
I think the main pain with move semantics was that it had to be bolted on to the language later. Consider that factor, they did an amazing job with it.
Compared to using std::auto?
Nah man. std::move is far easier to understand than trying to shove both concepts down operator=. std::unique is simply easier to use than std::auto by any real measurement.
The other advantage is that you can force only move semantics which allows enforcing things like ownership. Adding an operator doesn't destroy this advantage, but it is a bit silly since you're just adding line noise for something that really should be implicit anyway.
Unless you just literally don't like the spelling of "std::move" which seems pretty lame since it should be relatively rare anyway.
That'd invalidate a lot of programs. Just like how the new _ operator in Java is killing a lot of code right now.
Every symbol that can be used... has been used. "Move" is the meaning of the operator in any case. Its no less readable than say... Python's __lshift__ or __add__.
Consider: :=, <-=, <|, $,
Is there a new operator in some upcoming version of the language specification?
C++ has always been complex, but I defy anyone to read "Effective Modern C++" from cover to cover without clutching their pearls in horror.
Don't get me wrong, I actually like C++ in a weird way. There's nothing else out there that goes quite so far in putting you the programmer in charge while still attempting to let you work at a slightly higher level. But the price in cognitive load for this flexibility is just stupidly high.
Actually, Effective Modern C++ was pretty awesome. A good guide through all the complexity.
That is logically impossible, since it hasn't removed anything.
The myopic mantra "just don't use what you don't like" breaks down as soon as you work in a team, where you don't dictate what other's cannot use (let alone what code they inherit).
STL only started getting into compilers around '95, so we had no standard containers and dozens of different string implementations. The only part of the standard library widely available was iostreams, which is easily the most despised part of that library.
With no useful standard library to speak of, C++ devs were basically using the C standard library, rife with such shining gems of perfection as scanf(), strcat() and dear_hacker_please_inject_shellcode_here(). Since no generic containers were in sight, pretty much all 90s code I've had the pleasure to see was infested with macros. Pieces of exquisite beauty. I still have nightmares sometimes.
Then came the late 90s and early 2000s. The STL was widely supported, Boost started to gain ground and Andrei Alexandrescu released Modern C++ Design. Template metaprogramming slowly got out of hand and both code and errors were indecipherable.
The thing is, C++11 and beyond is the very opposite of this. Hairy template metaprogramming is replaced by simple and straightforward constexprs. Proper lambdas obsoleted functors, a gang of bloated design patterns (Visitor, Obeserver, Strategy, Command, Template Method, Decorator and so on) and several complicated lambda libraries from Boost.
Modern C++ is still a mess, but I believe it's way more elegant than ever before.
Yup. '92 C++ was what gave Java such a boost. If we'd somehow started with '98 C++, or better still C++11, Java might never have picked up so much momentum.
Also in 2000 I was writing K&R C on a HP-UX compiler, let alone the state of C++ compilers for writing portable code.
Yes. The experience in the early 90's meant everyone was looking for a saner choice. By the time C++ was the saner choice, Java had already received a giant boost.
Ignoring the nice work of PowerPlant , Turbo Vision and Object Windows Library, because they were too high level for C devs.
So Microsoft ripped off their Application Frameworks (Afx) prototype and we got MFC instead.
I have a much easier time holding the entire picture together but others are correct in saying you have to throw away old conceptions and ideas of the language. I personally have thrown away the way I think about C entirely (at least when I code in modern C++).
C++ is precisely useful because it's a better C: it has a C-like subset, and works directly with C data structures and function call interfaces. Plus it has features to do that kind of programming in a safer, more managed way.
I would absolutely not use C++ for anything that isn't in the area of "this should be ideally written in C, but that would bring in undue difficulties, risks and time".
The more C++ moves away from its focus of being a language for writing low-levelish systems middleware, the more it loses its relevance.
> Also, you have a ref counted pointer thread safe pointer!
Had those in 1997 using draft ISO C++, thanks.
The language has continued to grow, but it's growing in a rather different direction (or rather in a clear direction): towards a modern, preferred subset that _is_ lean, expressive, and elegant. While C++ is still far from my favorite language, I find C++ today to be far simpler, more expressive, and more elegant than at any other point in the past.