News for hackers. Stuff that matters.
Re:C++11 FAQ by spoondan on Thursday January 26, 2017 @10:37AM (#13492164)
This is perhaps one of the more unexpected opinions on C++ I've encountered. When I picked up C++ with Turbo C++ 3.0 in the early '90s, it was already widely regarded as an over-complex behemoth. Donald Knuth said of it in 1993, "Whenever the C++ language designers had two competing ideas as to how they should solve some problem, they said 'OK, we'll do them both'. So the language is too baroque for my taste." The last twenty years, there's no C++ that I would call lean, expressive, and elegant. You give the example of template meta-programming as something added more recently, but Erwin Unruh was printing the primes in compiler error messages not long after Knuth was knocking C++ as baroque. It makes me wonder if perhaps the issue isn't simply that over time you've become more aware of how complex the language has always been?

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.

Re:C++11 FAQ by cmrdporcupine on Thursday January 26, 2017 @10:40AM (#13492187)
Arguably the std::move stuff and the semantics around it have added uncomfortable complexity to the language, even if it might have been necessary. Other than that I think other advances in C++11 and beyond have made for a quite nicer language to work in.

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.

Re:C++11 FAQ by unscaled on Thursday January 26, 2017 @12:42PM (#13493400)
The 'original sin' of C++ is not having both references and pointers, but trying to remain compatible with C.

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.

Re:C++11 FAQ by cmrdporcupine on Friday January 27, 2017 @12:26PM (#13501113)
Yeah I agree that C compatibility is the fail. But it's also the only reason C++ is around today. There were plenty of other compiled systems languages with OO or module systems floated in the 80s, including the quite capable Modula-2/3s, various Pascal dialects, etc. Of all of them only C++ (and Objective-C because iOS) has any relevance today. And likely because there was a kind of path to trendy-OO for existing C programmers and shops.
Re:C++11 FAQ by JoeAltmaier on Thursday January 26, 2017 @10:42AM (#13492217)
Surely references have intrinsic value to the programmer? They're a pointer that can't be moved or rebased. Other languages have only references, and in C++ you can use that convention and not have any extra confusion.
Re:C++11 FAQ by makecheck on Thursday January 26, 2017 @10:55AM (#13492353)
Except that references still can be bad: invalidated later on by an object deletion, no matter how many rules were enforced to assign the reference to begin with. And in an almost-worse sense, "sometimes" references can prevent this and sometimes not. Just not good enough, while syntactically making it harder to tell that references are being used in function calls and such.
Re:C++11 FAQ by cousin_it on Thursday January 26, 2017 @12:59PM (#13493573)
References are crazy. There's no simple guideline to use them safely. Check this out:

    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.

Re:C++11 FAQ by qcoh on Thursday January 26, 2017 @02:04PM (#13494239)
Works for me in both C++03 and C++14? https://ideone.com/KhfGaN
Re:C++11 FAQ by cousin_it on Thursday January 26, 2017 @03:00PM (#13494773)
Your code is not the same as my code and you're probably new to C++. I suggest trying two changes:

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 :-)

Re:C++11 FAQ by qcoh on Thursday January 26, 2017 @04:27PM (#13495385)
Sorry, can you clarify? Adding the template argument causes a crash on idone, but I have no idea why that happens. Moreover, the output on my computer is always b\n.

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?

[0] http://stackoverflow.com/a/2784304

Re:C++11 FAQ by cousin_it on Thursday January 26, 2017 @06:10PM (#13496245)
So first of all, max("a", "b") expands to max<const char*>("a", "b"). It computes the maximum of two pointers, without looking at the characters at all. Comparing two pointers to unrelated objects is unspecified behavior, but in this case it usually returns the second pointer.

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.

Re:C++11 FAQ by qcoh on Thursday January 26, 2017 @06:15PM (#13496286)
Thank you for the explanation! I'll have to look out for that one...
Re:C++11 FAQ by cbsmith on Thursday January 26, 2017 @01:10PM (#13493694)
> Arguably the std::move stuff and the semantics around it have added uncomfortable complexity to the language, even if it might have been necessary.

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.

Re:C++11 FAQ by Koshkin on Thursday January 26, 2017 @01:56PM (#13494158)
No, the original sin was C's and it was the use of a separate "arrow" operator for accessing fields of a struct through a pointer. Other languages (C#, Java) successfully avoided that. C++ references allow templated code to be agnostic of whether an object is given by value or by reference, because the syntax is now more uniform.
Re:C++11 FAQ by dragontamer on Thursday January 26, 2017 @10:53AM (#13492340)
> Arguably the std::move stuff and the semantics around it have added uncomfortable complexity to the language

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.

Re:C++11 FAQ by cmrdporcupine on Thursday January 26, 2017 @10:55AM (#13492357)
My perhaps naive uneducated opinion: they should have added syntactic sugar for it instead of making it look like a function. A new operator perhaps.
Re:C++11 FAQ by kevinnk on Thursday January 26, 2017 @12:55PM (#13493526)
How does adding an operator help? There are two main advantage of having move semantics in the language and at least one of them relies on the fact that moves are implicit; you can write code that will move objects if supported and copy/destroy if not (for example, when returning an object or using an intermediate value in an expression). Adding an operator erases that advantage.

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.

Re:C++11 FAQ by dragontamer on Thursday January 26, 2017 @10:59AM (#13492395)
> A new operator perhaps.

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__.

Re:C++11 FAQ by sqeaky on Thursday January 26, 2017 @11:33AM (#13492744)
What if a hypothetical new operator used only characters already not allowed in identifiers and composed of characters not allowed in contiguous operator sequences.

Consider: :=, <-=, <|, $,

Re:C++11 FAQ by cbsmith on Thursday January 26, 2017 @01:18PM (#13493768)
AFAIK, _ isn't an operator in Java (http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#...). The language does allow _ to be used as a separator in numeric literals.

Is there a new operator in some upcoming version of the language specification?

Re:C++11 FAQ by yrro on Thursday January 26, 2017 @02:22PM (#13494386)
_ is a keyword in Java 9.
Re:C++11 FAQ by cbsmith on Friday January 27, 2017 @02:35AM (#13498327)
It isn't an operator though, right?
Re:C++11 FAQ by yrro on Friday January 27, 2017 @11:10AM (#13500571)
That's correct, I only intended to clarify your point.
Re:C++11 FAQ by deong on Thursday January 26, 2017 @12:16PM (#13493169)
The thing is that something like computing primes with template instantiations was always a little weird and came with problems around sensible build processes. The rules were...well...complicated, but not that complicated. You had ADL rules that were weird, but basically, you could view a lot of the template hackery as a weird thing that you could understand without too much trouble, but probably didn't need to. That's much less true with most of the C++-11/14/17 features.

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.

Re:C++11 FAQ by cbsmith on Thursday January 26, 2017 @01:06PM (#13493652)
> C++ has always been complex, but I defy anyone to read "Effective Modern C++" from cover to cover without clutching their pearls in horror.

Actually, Effective Modern C++ was pretty awesome. A good guide through all the complexity.

Re:C++11 FAQ by deong on Thursday January 26, 2017 @01:52PM (#13494114)
Oh, the book is awesome. I mean the fact that such a book had to be written is a pretty rough statement about the language.
Re:C++11 FAQ by kazinator on Thursday January 26, 2017 @03:05PM (#13494813)
> I find C++ today to be far simpler, more expressive

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).

Re:C++11 FAQ by huhtenberg on Thursday January 26, 2017 @11:19AM (#13492611)
I started with C++ around '92, but you are right, C++ was already complex back then, but it was still manageable, you could, sort of, hold its larger picture entirely in your head and still had some elegance to it.
Re:C++11 FAQ by unscaled on Thursday January 26, 2017 @12:18PM (#13493187)
1992 was just the year MFC came out. I would go as far as saying that C++ of the early '90s was at its Nadir of inelegance. I'd go as far as saying that C++ frameworks of the early 90s were the absolute nadir of elegance.

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.

Re:C++11 FAQ by cbsmith on Thursday January 26, 2017 @01:09PM (#13493686)
> I would go as far as saying that C++ of the early '90s was at its Nadir of inelegance.

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.

Re:C++11 FAQ by pjmlp on Thursday January 26, 2017 @02:15PM (#13494331)
Java picked momentum because in 1996, ANSI C++98 wasn't a thing, each compiler was catching up with the standard and many library vendors just gave use C libraries with us having to write C++ wrappers ourselves.

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.

Re:C++11 FAQ by cbsmith on Friday January 27, 2017 @02:36AM (#13498332)
> Java picked momentum because in 1996, ANSI C++98 wasn't a thing, each compiler was catching up with the standard and many library vendors just gave use C libraries with us having to write C++ wrappers ourselves.

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.

Re:C++11 FAQ by pjmlp on Thursday January 26, 2017 @02:13PM (#13494303)
> 1992 was just the year MFC came out.

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.

Re:C++11 FAQ by huhtenberg on Thursday January 26, 2017 @02:49PM (#13494654)
OWL and TurboVision... now these are names I haven't heard in a long time. I remember the company I interned at was looking for TurboVision programmers at some point, none were found, soin a true Russian fashion they just wrote their own clone of it.
Re:C++11 FAQ by pjmlp on Thursday January 26, 2017 @03:49PM (#13495124)
I used Turbo Vision in Turbo Pascal 6/7, then migrated to Turbo Pascal for Windows 1.5 with OWL and eventually to Turbo C++ 3.1 with OWL.
Re:C++11 FAQ by banachtarski on Thursday January 26, 2017 @11:40AM (#13492810)
As a dissenting opinion from someone who has not quite 20 years of experience with C/C++ but 14, modern C++ is what brought me back to the language. The idioms allow me to use the language more functionally. More importantly, the STL is actually usable now and you can just code using it and std::algorithm without thinking of the nuts and bolts of move assignment and stuff at all. In the case where you need performance, you have the paradigm at your disposal. Also, you have a ref counted pointer thread safe pointer! A means of transferring ownership so heap allocated objects can also follow the same RAII pattern!

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++).

Re:C++11 FAQ by kazinator on Thursday January 26, 2017 @03:12PM (#13494860)
C++ still cannot compete with proper high level languages in this area.

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.

Re:C++11 FAQ by MichaelMoser123 on Saturday January 28, 2017 @09:11PM (#13511369)
just be careful with those ref counted pointers: shared_ptr/weak_ptr introduce a lot of atomic variable access. if you use them from a single thread then that's pure overhead.
Re:C++11 FAQ by banachtarski on Tuesday January 31, 2017 @02:54AM (#13528611)
Yes, of course. A big chunk of my time at various previous companies was removing usage of such things when not necessary. It's also not "a lot" of atomic variable access but you do need a strong fence to provide the correct semantics (so it is some). To what degree "a lot" or "some" is depends obviously on what you're doing.
Re:C++11 FAQ by cbsmith on Thursday January 26, 2017 @01:08PM (#13493673)
Honestly, back in '92 the language seemed easy, but the practice was hideously complex and error prone. Most people still couldn't even figure out how to do exceptions properly. I would argue that today, the language is more complex, but the practice is comparatively simpler (still complex as a ll get out, but compared to '92...).