notes-computer-programming-programmingLanguageDesign-prosAndCons-Cplusplus

apparently in this video a Go inventor talks about why C++ is hard to read:

http://www.youtube.com/watch?feature=player_embedded&v=5kj5ApnhPAE

---

" Little shop of horrors

There was so much talk about how not to use C++ that it occurred to me that maybe this wasn’t the problem of incompetent programmers, but that straightforward C++ is plain wrong. So if you just learn the primitives of the language and try to use them, you’re doomed.

C++ has an excuse for that: backward compatibility — in particular compatibility with C. You might think of the C subset of C++ as bona fide assembly language which you shouldn’t use it in day-to-day programming, except that it’s right there on the surface. If you reach blindly into your C++ toolbox, you’re likely to come up with naked pointers, for loops, and all this ugly stuff.

A well known example of what not to do is to use malloc to dynamically allocate memory, and free to deallocate it. malloc takes a count of bytes and returns a void pointer, which you have to cast to something more usable — it would be hard to come up with worse API for memory management. Here’s an example of really bad (but almost correct, if it weren’t for the possibility of null pointer dereference) code:

struct Pod { int count; int * counters; };

int n = 10; Pod * pod = (Pod *) malloc (sizeof Pod); pod->count = n pod->counters = (int *) malloc (n * sizeof(int)); ... free (pod->counters); free (pod);

Hopefully, nobody writes code like this in C++, although I’m sure there are a lot of legacy apps with such constructs, so don’t laugh.

C++ “solved” the problem of redundant casting and error-prone size calculations by replacing malloc and free with new and delete. The corrected C++ version of the code above would be:

struct Pod { int count; int * counters; };

int n = 10; Pod * pod = new Pod; pod->count = n; pod->counters = new int [n]; ... delete [] pod->counters; delete pod;

BTW, the null pointer dereference problem is solved too, because new will throw an exception when the system runs out of memory. There is still a slight chance of a memory leak if the second new fails (But how often does that happen? Hint: how big can n get?) So here’s the really correct version of the code:

class Snd { Sophisticated New Data public: Snd (int n) : _count(n), _counters(new int [n]) {} ~Snd () { delete [] _counters; } private: int _count; int * _counters; };

Snd * snd = new Snd (10); ... delete snd;

Are we done yet? Of course not! The code is not exception safe.

The C++ lore is that you should avoid naked pointers, avoid arrays, avoid delete. So the remedy for the lameness of malloc is operator new, which is also broken because it returns a dangerous pointer and pointers are bad.

We all know (and have scars on our faces to prove it) that you should use the Standard Library containers and smart pointers whenever possible. Oh, and use value semantics for passing things around. No wait! Value semantics comes with a performance penalty because of excessive copying. So what about shared_ptr and vectors of shared_ptr? But that adds the overhead of reference counting! No, here’s a new idea: move semantics and rvalue references.

I can go on and on like this (and I often do!). Do you see the pattern? Every remedy breeds another remedy. It’s no longer just the C subset that should be avoided. Every new language feature or library addition comes with a new series of gotchas. And you know a new feature is badly designed if Scott Meyers has a talk about it. (His latest was about the pitfalls of, you guessed it, move semantics.) " -- http://bartoszmilewski.com/2013/09/19/edward-chands/

" Concurrency and Parallelism

It’s been 8 years since Herb Sutter famously exclaimed: The Free Lunch is Over! Ever since then the big C++ oil tanker has been slowly changing its course. It’s not like concurrency was invented in 2005. Posix threads have been defined in 1995. Microsoft introduced threads in Windows 95 and multiprocessor support in Windows NT. Still, concurrency has only been acknowledged in the C++ Standard in 2011.

C++11 had to start from scratch. It had to define the memory model: when and in what order memory writes from multiple threads become visible to other threads. For all practical purposes, the C++ memory model was copied from Java (minus some controversial guarantees that Java made about behavior under data races). In a nutshell, C++ programs are sequentially consistent if there are no data races. However, since C++ had to compete with the assembly language, the full memory model includes so called weak atomics, which I would describe as portable data races, and recommend staying away from.

C++11 also defined primitives for thread creation and management, and basic synchronization primitives as defined by Dijkstra and Hoare back in the 1960s, such as mutexes and condition variables. One could argue whether these are indeed the right building blocks for synchronization, but maybe that doesn’t really matter because they are known not to be composable anyway. The composable abstraction for synchronization is STM (Software Transactional Memory), which is hard to implement correctly and efficiently in an imperative language. There is an STM study group in the Standards Committee, so there is a chance it might one day become part of the Standard. But because C++ offers no control over effects, it will be very hard to use properly.

There was also a misguided and confusing attempt at providing support for task-based parallelism with async tasks and non-composable futures (both seriously considered for deprecation in C++14). Thread-local variables were also standardized making task-based approach that much harder. Locks and condition variables are also tied to threads, not tasks. So that was pretty much a disaster. The Standards Committee has the work cut out for them for many years ahead. That includes task-based composable parallelism, communication channels to replace futures (one would hope), task cancellation and, probably longer term, data-driven parallelism, including GPU support. A derivative of Microsoft PPL and Intel TBB should become part of the Standard (hopefully not Microsoft AMP).

Let’s take a great leap of faith and assume that all these things will be standardized and implemented by, say, 2015. Even if that happens, I still don’t think people will be able to use C++ for mainstream parallel programming. C++ has been designed for single thread programming, and parallel programming requires a revolutionary rather than evolutionary change. Two words: data races. Imperative languages offer no protection against data races — maybe with the exception of D.

In C++, data is shared between threads by default, is mutable by default, and functions have side effects almost by default. All those pointers and references create fertile grounds for data races, and the vulnerability of data structures and functions to races is in no way reflected in the type system. In C++, even if you have a const reference to an object, there is no guarantee that another thread won’t modify it. Still worse, any references inside a const object are mutable by default.

D at least has the notion of deep constness and immutability (no thread can change an immutable data structure). Another nod towards concurrency from D is the ability to define pure functions. Also, in D, mutable objects are not shared between threads by default. It is a step in the right direction, even though it imposes runtime cost for shared objects. Most importantly though, threads are not a good abstraction for parallel programming, so this approach won’t work with lightweight tasks and work-stealing queues, where tasks are passed between threads.

But C++ doesn’t support any of this and it doesn’t look like it ever will.

Of course, you might recognize all these pro-concurrency and parallelism features as functional programming — immutability and pure functions in particular. At the risk of sounding repetitive: Haskell is way ahead of the curve with respect to parallelism, including GPU programming. That was the reason I so easily converted to Haskell after years of evangelizing good programming practices in C++. Every programmer who’s serious about concurrency and parallelism should learn enough Haskell to understand how it deals with it. There is an excellent book by Simon Marlow, Parallel and Concurrent Programming in Haskell. After you read it, you will either start using functional techniques in your C++ programming, or realize what an impedance mismatch there is between parallel programming and an imperative language, and you will switch to Haskell. "

--

" Bartosz Milewski Says:

September 19, 2013 at 6:26 pm

@Aaron. I would recommend Bjarne’s book, “A tour of C++” as a good introduction to the language: http://www.stroustrup.com/Tour.html . "

--

upvote

scythe 2 days ago

link

Well, there is also the difficulty that there has not been, save Ada, a serious and concerted effort to replace C and C++ for so many of the things that they are used for. Except for Ada, no other modern language is suitable for writing things like kernels, drivers, emulators, etc; except for Ada, basically all modern languages are dependent on garbage collection.

So if you want to complain about C, remember that the only serious alternative is and has been Ada, and ask yourself why you're not using Ada, why operating systems and window managers, mupen64plus and Wayland, et cetera don't use Ada, and the truth is: people like C more than Ada.

Ada is the anti-C++. It's the answer to every criticism. It's also basically unheard of outside of situations where people really, really need safety cf. airline industry. In fact most of the people who complain about C++ would never even consider Ada. The author of the article seems to be unaware it even exists, which says a lot.

The takeaway is that safety is overrated, consistency is overrated, reliability is overrated, because if we really cared about these things... we'd use Ada. And we don't, because "Ada is annoying!".

reply

upvote

graue 2 days ago

link

Rust[1] is aimed squarely at this use case. The GC and runtime are optional. A toy kernel[2] and Linux kernel module[3] have already been written in it. The language is young and still unstable, but it's being designed by veteran C++ programmers with the goal of using it for a safer, faster, more maintainable successor[4] to the browser engine in Firefox. Worth checking out!

[1] http://www.rust-lang.org/

[2] https://github.com/charliesome/rustboot

[3] http://thechangelog.com/rust-ko-a-minimal-linux-kernel-modul...

[4] https://github.com/mozilla/servo

reply

upvote

--

hackinthebochs 2 days ago

link

I love coding in C++. The feeling of being so close to the metal that your actions are directly controlling the machine is something that was lost immediately when I moved to Java. It even more of a disconnect in higher level languages.

reply

upvote

twoodfin 2 days ago

link

I have sort of the opposite feeling: I love that in C++ I can create very nice abstractions while being fairly confident that the compiler will transform them into code with C-like performance. That is, as long as you know what to avoid (namely: heap allocations and unnecessary copying).

reply

upvote

Pxtl 2 days ago

link

This is the thing. This is what gets lost. C++ was designed with the premise that the language allows you to use it both in a C-like context and a Java-like context.

The problem is that some of the baggage of the former interferes with the latter. C++ is danged ugly in some places in ways that could be expressed cleanly in higher-level languages.

That's what C++ coders want - C++ with modules and real generics and fast compile-times and ways to cleanly implement and use garbage-collection if you so choose. A language that lets you say incredibly complicated and detailed things, and then lets you abstract them away into a library or a class or some other unit of organization that lets another coder use your stuff without absorbing the complexity.

All these "C++ replacements" assume that the solution is to gut out all the C-like stuff. What they should be looking to do is giving developers clean alternatives to the C-like stuff, including ways for the hardcore developers to provide their own clean alternatives to the C-like stuff. Don't give us garbage collection, give us the tools to write libraries that provide clean garbage collection to a developer.

reply

--

upvote

bluecalm 2 days ago

link

There is a lot of crap in C++ which doesn't help with performance at all: class hierarchy with all the inheritance/friends/virtual/constructors/destructors, godawful syntax, template model, exception handling, 101 ways to do the same thing, lack of package/module handling etc. Rob Pike addresses those in the article.

Yes, Go is slower but it's not slower because of fixing those errors, it's slower because it introduces different features suitable for its niche (GC, reflection etc) Rust takes similar approach to avoid C++ design mistakes and doesn't sacrifice performance in doing so.

Those mistakes (mainly the whole "object model" thing) is what he is saying in the article. Pointing out performance of Go isn't really an argument against his point.

reply

upvote

RogerL? 2 days ago

link

Templates do help with performance. Look up the performance characteristics of qsort (C) vs std::sort (templatized C++ sort).

reply

--

 internal tools. I'll definitely start my next one in Go. I might even translate my last one to Go sometime.

reply

upvote

pmelendez 2 days ago

link

> "I'd be interested in hearing something from an expert C++ programmer who has really given go a try and decided it's not their cup of tea."

I am not a C++ expert but I have programmed a fairly amount of C++ code so I will give you my two cents.

I use C++ because a blend of three things:

If I would care just in a subset of that tuple I probably will code in something else.

For instance, if for some project performance is not an issue, I will probably use a higher level language like Python or Scheme. If I am feeling that Abstraction is not as important as performance and portability I will use C.

When I care about the three of them I feel there are not too many options.

reply

--

" That said, I can report on what I prefer right now, knowing what I already know (having spent 4 years programming java professionally as well) - and I truly prefer a more functional approach that comes a lot more easily in languages that support closures and first class functions. It also strikes me that many of the best practices in java / c++ are basically moving towards more functional programming (prefer composition to inheritance, make objects immutable by default, interfaces over classes when possible, dependency injection / referential transparency and parameterizing methods by interfaces e.g functions). "

-- " very few C++ programmers are going to jump into a garbage collected language. If they were, they would have moved long ago. Most of the times you need C++ nowadays are because a GC language simply won't do. "

"

upvote

vidarh 2 days ago

link

Even just reading any of the dozens of long discussions about adding GC to C++ might have been enlightening. It's not like this has not been discussed over and over and over over the last twenty years.

The point being that in any discussion about new C++ features the central point always tends to devolve to:

What is the cost to me if I don't use this feature in my programs?

If I don't use exceptions, I don't pay for them. If I don't use virtual member functions, I don't pay for them. If I don't use RTTI, I don't pay for it.

In other words: If you want/expect C++ programmers to switch to your language, don't make people pay for what they don't want to use.

Support for plugging in a GC would not violate that, but enabling/requiring a GC by default most certainly does.

reply "

" jre 2 days ago

link

One of the major (the only?) reason I still write C++ code is the amount of libraries available. I'm writing computer vision stuff and all the important libraries (OpenCV?, PCL, nonlinear optimization stuff) are in C++...

Sure there are bindings, but they are often incomplete and not quite stable.

I will switch the day a language allows me to transparently call my existing C++ library, without having to spend time writing and debugging swig/boost::python/whatever wrappers. "

" simias 2 days ago

link

There is one feature of go that prevents me for considering it when I want to write "low level" code: garbage collection.

It's probably very silly but in my mind that puts it next to Java, above C and C++ in the "grand scale of programming languages".

Oh, and also I don't like garbage collection, so there's that. I'm sure some day someone will explain to me what's the point of it because I still don't get it.

reply

upvote

Arelius 2 days ago

link

If somebody thinks that a language with GC could fill the same niche as C++, then well, they must work at Google.

Ohh... huh...

reply

upvote

CmonDev? 2 days ago

link

I think you should be given a choice whether to use GC. Now that's a killer feature.

reply "

--

" The programs I'm writing run on one machine with restricted memory, and they need to be highly, highly performant. The execution time is measured in tens of milliseconds, and during that time we do a lot mathematics and processing. SIMD is our close, beloved friend. In that context, I don't think Go is an appropriate language, due to its garbage collector, its lack of precise control over where objects go in memory, and the overhead of method calls. "

--

upvote

stelonix 2 days ago

link

I can't speak for him, but the issues that make Go not interesting at all to me (and I believe, to a lot of other C++ coders) are automatic GC, lack of generics and lack of template metaprogramming.

The thing with Go is that it is (was?) marketed as a system's programming language. Go might work as a replacement for Java, but Java is not for system programming.

Whoever decided to say Go was capable of it either has no idea what systems programming means or was being deceitful. Go can not replace C++; these languages don't solve the same problems.

reply

upvote

Pxtl 2 days ago

link

I always say, all of these "replacements for C++" don't feel like C++, they feel like statically-typed Python. Which is great, if you want statically-typed Python. There's a lot of fantastic uses for statically-typed Python.

But they're not C++. As soon as you tie the whole language to a garbage-collector and leave out any real mechanism for metaprogramming or even simple generics, you've lost me.

Pure text-based lexical macros like templates are a weapon of last-resort for language design... but it's not an optional one. Dynamic-typed languages cheat by offering a simple "exec" statement/function. Static languages have a religious objection to offering a first-party preprocessor, because they have the hubris to believe they can solve every possible problem ever within their language.

Nobody is that good at programming language design. Not Pike, not Gosling, not Ritchie, not anybody. The difference is that Ritchie's team knew that, and didn't try and pretend that every single thing could be easily and performantly expressed in their language, and made the hackish ugly macro system to solve the edge cases... and it worked.

reply

--

"what's wrong with c++ templates?"

http://people.cs.uchicago.edu/~jacobm/pubs/templates.html

--

upvote

legulere 2 days ago

link

Two exemplary reasons why Go occupies a different space: - Mandatory garbage collection. Sometimes you need more control over memory than being able to use just one standard garbage collection. - No dynamic linking. Just think about what would happen if qt, webkit or llvm would be statically linked in in all programs using them.

--

C++'s "you only pay for features you use"

--

what's wrong with c++ exceptions?

" The downside of C++ exceptions is you can’t tell (without the source and the impetus to check) if any function you call may throw an exception. In addition to worrying about resource leaks and destructors, you have to worry about RAII and transactional semantics to ensure your methods are exception safe in case they are somewhere on the call stack when an exception is thrown. In solving one problem, C++ created another.

So the designers of Java sat down, stroked their beards and decided that the problem was not exceptions themselves, but the fact that they could be thrown without notice; hence Java has checked exceptions. "

" The usual counter argument to this statement is that error handling in general is hard, and exceptions make it easier, not harder. While there is a lot of truth in that, the issue of the learning curve remains: complex language features often do help experienced programmers simplify their code, but the beginners mostly see the added pain of learning. To use exceptions in production code, a C++ programmer not only has to learn the language mechanism, but also the best practices of programming with exceptions. How soon a beginner learns to never throw from a destructor? Or use exceptions for exceptional conditions only and never for the normal code flow? Or catch by reference, and not by value or a pointer? How about usefulness (or the lack or thereof) of exception specifications? Exception safety guarantees? Dark corners, such as polymorphic throwing? "

"

Articles » Languages » C / C++ Language » General

Next [Next] Article Browse Code Stats Revisions (4) Alternatives Comments & Discussions (57)

C++ Exceptions: Pros and Cons By Nemanja Trifunovic, 28 Dec 2009 4.91 (97 votes)

Prize winner in Competition "Best C++/MFC article of July 2009"

    Introduction
    Arguments for using Exceptions
        Exceptions separate error-handling code from the normal program flow and thus make the code more readable, robust, and extensible.
        Throwing an exception is the only clean way to report an error from a constructor.
        Exceptions are hard to ignore, unlike error codes.
        Exceptions are easily propagated from deeply nested functions.
        Exceptions can be, and often are, user defined types that carry much more information than an error code.
        Exception objects are matched to the handlers by using the type system.
    Arguments against using Exceptions
        Exceptions break code structure by creating multiple invisible exit points that make code hard to read and inspect.
        Exceptions easily lead to resource leaks, especially in a language that has no built-in garbage collector and finally blocks.
        Learning to write Exception safe code is hard.
        Exceptions are expensive and break the promise to pay only for what we use.
        Exceptions are hard to introduce to legacy code.
        Exceptions are easily abused for performing tasks that belong to normal program flow.
    Conclusion"

" Monday, October 13, 2003

Exceptions

People have asked why I don't like programming with exceptions. In both Java and C++, my policy is:

    Never throw an exception of my own
    Always catch any possible exception that might be thrown by a library I'm using on the same line as it is thrown and deal with it immediately.

The reasoning is that I consider exceptions to be no better than "goto's", considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto's:

    They are invisible in the source code. Looking at a block of code, including functions which may or may not throw exceptions, there is no way to see which exceptions might be thrown and from where. This means that even careful code inspection doesn't reveal potential bugs.
    They create too many possible exit points for a function. To write correct code, you really have to think about every possible code path through your function. Every time you call a function that can raise an exception and don't catch it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn't think about.

A better alternative is to have your functions return error values when things go wrong, and to deal with these explicitly, no matter how verbose it might be. It is true that what should be a simple 3 line program often blossoms to 48 lines when you put in good error checking, but that's life, and papering it over with exceptions does not make your program more robust. I think the reason programmers in C/C++/Java style languages have been attracted to exceptions is simply because the syntax does not have a concise way to call a function that returns multiple values, so it's hard to write a function that either produces a return value or returns an error. (The only languages I have used extensively that do let you return multiple values nicely are ML and Haskell.) In C/C++/Java style languages one way you can handle errors is to use the real return value for a result status, and if you have anything you want to return, use an OUT parameter to do that. This has the unforunate side effect of making it impossible to nest function calls, so result = f(g(x)) must become:

    T tmp;
    if (ERROR == g(x, tmp))
         errorhandling;
    if (ERROR == f(tmp, result))
         errorhandling;

This is ugly and annoying but it's better than getting magic unexpected gotos sprinkled throughout your code at unpredictable places. "

" C++ exceptions offer none of these features. "Exception-safe" C++ code can't handle errors which happen when it tries to release resources; "exception-unsafe" C++ code will leak resources, most frequently memory; and once you throw an exception, the call stack is lost. This means that even separating your code to several processes and executing code like *(int*)0 = 0; upon error is a better way to handle errors than C++ exceptions: at least the memory is going to be reclaimed by the operating system, and you can typically have it save a snapshot of the process, so that you can open it in a debugger and see where the error happened. A recommendation to "ban" exceptions is probably over the edge, but think a lot before using C++ exceptions, or a feature that implicitly depends on them, such as constructors and overloaded operators, which have no other way to report an error. What C++ calls "exceptions" is as unlikely to give you the benefits people get from exceptions in other languages as what C++ calls "classes" is unlikely to give you the benefits of OO. "

" Exception specs are bad because they're weakly enforced, and therefore don't actually accomplish much, and they're also bad because they force the run-time to check for unexpected exceptions so that they can terminate(), instead of invoking UB, this can waste a significant amount of performance.

So in summary, exception specs aren't enforced strongly enough in the language to actually make code any safer, and implementing them as specified was a big performance drain. "

" C++ does not programmatically enforce exception specifications at compile time "

" Exceptions make it really easy to write code where an exception being thrown will break invariants and leave objects in an inconsistent state. They essentially force you to remember that most every statement you make can potentially throw, and handle that correctly. Doing so can be tricky and counter-intuitive."

" Methods like RAII, which C++ programmers love to mention as the ultimate solution to this problem, go a long way to protect against this. But they aren't a silver bullet. It will make sure you release resources on a throw, but doesn't free you from having to think about corruption of object state and callers seeing intermediate values. So, for a lot of people, it's easier to say, by fiat of coding style, no exceptions. If you restrict the kind of code you write, it's harder to introduce these bugs. If you don't, it's fairly easy to make a mistake. "

---

" ...C++ is probably the most inconsistent programming language ever made, syntax-wise. We have the macros, the goto/labels, the horde (hoard?) of undefined-/unspecified-/implementation-defined behavior, the poorly-defined integer types, all the implicit type promotion rules, special-case keywords like friend, auto, register, explicit... And so on. Someone could probably write several thick books of all the weirdness in C/C++. So why are people reacting against this particular inconsistency, which is a minor flaw in comparison to many other far more dangerous features of the language? "

--

"

AK You have to be a different kind of person to love C++. It is a really interesting example of how a well-meant idea went wrong, because [C++ creator] Bjarne Stroustrup was not trying to do what he has been criticized for. His idea was that first, it might be useful if you did to C what Simula did to Algol, which is basically act as a preprocessor for a different kind of architectural template for programming. It was basically for super-good programmers who are supposed to subclass everything, including the storage allocator, before they did anything serious. The result, of course, was that most programmers did not subclass much. So the people I know who like C++ and have done good things in C++ have been serious iron-men who have basically taken it for what it is, which is a kind of macroprocessor. I grew up with macro systems in the early ’60s, and you have to do a lot of work to make them work for you—otherwise, they kill you.

SF Well, C++, after all, was programmed as a macro processor, in essence.

AK Yes, exactly. But so was Simula. " -- Alan Kay, http://queue.acm.org/detail.cfm?id=1039523

--

upvote

MetaCosm? 45 days ago

link

I think a lot of people HAVE made the case convincingly, at least well enough for me. I have worked in major C++ shops that ban the use of exceptions (and enforce it).

Just to add another person who regrets exceptions to the big pile, http://250bpm.com/blog:4 (The ZMQ Author)

"Thus, the error handling was of utmost importance. It had to be very explicit and unforgiving.

C++ exceptions just didn't fill the bill. They are great for guaranteeing that program doesn't fail — just wrap the main function in try/catch block and you can handle all the errors in a single place.

However, what's great for avoiding straightforward failures becomes a nightmare when your goal is to guarantee that no undefined behaviour happens. The decoupling between raising of the exception and handling it, that makes avoiding failures so easy in C++, makes it virtually impossible to guarantee that the program never runs info undefined behaviour.

With C, the raising of the error and handling it are tightly couped and reside at the same place in the source code. This makes it easy to understand what happens if error happens..."

upvote

pjmlp 45 days ago

link

That is a problem with the way exceptions work in C++, not with the exceptions as concept.

C++ exception's design suffer from being added to the language in the last years of the language's design and having to support the possibility of being turned off if desired.

This, coupled with the manual resource management of the language is with lead to some of the issues with exceptions in C++.

Not all languages with exception's support suffer from the same problems.

---

how to write "modern C++":

http://ecn.channel9.msdn.com/events/LangNEXT2012/LangNEXTHerbSutterCpp.pptx

" Core Language auto range-for lambdas move semantics uniform initialization

Libraries smart pointers async and future

Taste of C++11: string flip( string s ) { reverse( begin(s), end(s) ); return s; }

int main() { vector<future<string>> v;

    v.push_back( async([]{ return flip(" ,olleH"); }) );
    v.push_back( async([]{ return flip(  ".gnaL"); }) );
    v.push_back( async([]{ return flip("\n!TXEN"); }) );
    for( auto& e : v ) {
        cout << e.get();
    }}

always there: scoped lifetimes by construction (stack, member)  strongly exception-safe  deterministic

asynchrony  201x’s best friend

lambdas invasion of the functionals capture by ref or by value

move semantics

 the semantics of value types (no pointers! declared lifetime!) +  the efficiency of reference types (no deep copying!)

program is guaranteed to allocate only three strings

 high compute / low latency

Smart Pointers: Portable Type & Memory Safety

C++98 widget* pw = new widget(); delete pw;

C++11 auto pw = make_shared<widget>();

C++98 class node { vector<node*> children; node* parent;

C++11 class node { vector<unique_ptr<node>> children; node* parent;

Use unique_ptr by default, and shared_ptr/weak_ptr to express shared ownership/observation. Avoid “new” and “delete.” Use a non-owning * or & to observe an object that will outlive you.

Then: circle* p = new circle( 42 ); vector<shape*> vw; load_shapes( vw ); for( vector<circle*>::iterator i = vw.begin(); i != vw.end(); ++i ) { if( (*i)->weight() > 100 ) cout << i << “ is a match\n”; } for( vector<circle*>::iterator i = vw.begin(); i != vw.end(); ++i ) { delete *i; } delete p;

now:

auto p = make_shared<circle>( 42 ); auto vw = load_shapes(); for( auto& s : vw ) { if( s->weight() > 100 ) cout << *s << “ is a match\n”; }

With C++11, modern C++ code is clean, safe, and fast.

As clean and safe as any other modern language. “When used in a modern style.” – Bjarne Stroustrup

Was always fast. Now even faster. Move semantics, constexpr.

C++ Values & Tenets Never compromise on performance and control. Efficient abstraction (e.g., inlining by default) Flexibility to express exactly what you need (e.g., specialization) Exact control over memory layout (e.g., stack/member allocation) Determinism and ordering WYSIWYG (e.g., stack/member lifetime)

Deeply believe in trust and zero overhead. “Leave no room for a language lower than C++” other than asm “Zero overhead” / “Don’t pay for what you don’t use” “Trust the programmer” (  pitfalls! still give usability, guard rails) “Always provide a way to open the hood and get down to the metal”

Priorities He says: “Provide default-on guard rails and programmer productivity too, but never at the expense of performance and control.”

She says: “Provide performance and control too, but never at the expense of always-on guard rails and programmer productivity.”

both agree: virtual auto / var lambda functions range for / foreach immutable objects expr templates / LINQ futures ref types value types await * static if * modules * parallel algorithms * thread-safe containers * hash control & much more

“Native” C++ recommended / opt-in smart pointers garbage collection *

default assumptions inlinability predictable obj layout deterministic ordered (e.g., dtor) (big-Oh of operations) power-ups lambda ref

specializable templates (hash control)
value capture

“Managed” Java/C# always-on / default-on garbage collection virtual machine metadata default assumptions virtual dispatch dynamic obj layout nondeterministic unordered (e.g., fzer)

simplifications lambdas ref-capture always one-shot/type-erased C<T> (hash automation)

Modern C++ is clean, safe, and fast. Strong abstraction: Type-safe OO and generic code for modeling power, without sacrificing control and efficiency. Full control over code and memory: You can always express what you want to do. You can always control memory and data layout exactly. Pay-as-you-go efficiency: No mandatory overheads. “The going word at Facebook is that ‘reasonably written C++ code just runs fast,’ which underscores the enormous effort spent at optimizing PHP and Java code. Paradoxically, C++ code is more difficult to write than in other languages, but efficient code is a lot easier.” – Andrei Alexandrescu "

-- http://ecn.channel9.msdn.com/events/LangNEXT2012/LangNEXTHerbSutterCpp.pptx

-- gee this is pretty verbose:

  1. include <cstdio> struct X { int a; const char * s; explicit X(const char * s, int a = 42) : a(a), s(s) {}; void say_it() const { std::printf("%s %dn", s, a); } };

int main() { X("the answer is").say_it(); }

---

" The rule of three (also known as the Law of The Big Three or The Big Three) is a rule of thumb in C++ that claims that if a class defines one of the following it should probably explicitly define all three:[1]

    destructor
    copy constructor
    copy assignment operator

...

If one of these functions is used without first being declared by the programmer it will be implicitly implemented by the compiler with the default semantics of performing the said operation on all the members of the class.

...

The Rule of Three claims that if one of these had to be defined by the programmer, it means that the compiler-generated version does not fit the needs of the class in one case and it will probably not fit in the other cases either.

...

 The default semantics are:
    Destructor - Call the destructors of all the object's class-type members
    Copy constructor - Construct all the object's members from the corresponding members of the copy constructor's argument, calling the copy constructors of the object's class-type members, and doing a plain assignment of all non-class type (e.g., int or pointer) data members
    Copy assignment operator - Assign all the object's members from the corresponding members of the assignment operator's argument, calling the copy assignment operators of the object's class-type members, and doing a plain assignment of all non-class type (e.g., int or pointer) data members.

---

With the advent of C++11 the rule of three probably needs to be broadened to the rule of five as C++11 implements move semantics,[5] allowing destination objects to grab (or steal) data from temporary objects. The following example also shows the new moving members: move constructor and move assignment operator "

---

" A basic principle of C++ is that the operations performed whenan object’s life ends are the exact reverse of the operationsperformed when the object’s life starts.

struct A { A() : id(count++) { printf("A(%d)n", id); }; ~A() { printf("~A(%d)n", id); }; int id; static int count; };

int main() { A array[4]; }

A(0) A(1) A(2) A(3) ~A(3) ~A(2) ~A(1) ~A(0) "

---

" E.g. why I can't make a generic (template) function virtual "

"

You can't make a member function template virtual because it's just a template, the function doesn't exist until it's statically instantiated. Instantiation can happen across units of compilation, making it impossible for the compiler to generate a vtable with all the instantiations within it "

--

" Basically, coding in C/C++ requires an intimate knowledge of how the compiler works, and sometimes even how the target chip works. C/C++ software projects of notable size oftentimes cannot be simply recompiled/linked to a different target architecture without changing things like compiler flags, the makefile, and even the application code itself. That makes it a non-portable, leaky abstraction, and dramatically increases the amount of knowledge that's required of a C/C++ developer. "

--

upvote

praptak 16 hours ago

link
 A fun fact about sequence points. C++ has switched from "sequence points" to "sequenced before/sequenced after" relation. And it is not really "all" previous side-effects that are guaranteed to be visible after the sequence point but only those associated with the sequence point.

In 'foo(b++, a++ && (a+b));' the sequence point introduced by the '&&' only makes the 'a' see the effect 'a++' but the 'b' might not see the 'b++' (function args are not sequenced in C nor C++).

coldpie 12 hours ago

link

Why on Earth are you writing a statement like that in the first place?

reply

upvote

praptak 11 hours ago

link

Exaggerated example to show a pattern. A (hopefully) less outrageous (but still bad!) example of the dangers of sequencing:

    foo(std::unique_ptr<T1>{new T1 },
        std::unique_ptr<T2>{new T2 }); 

This one's from GotW? #102.

reply

upvote

alok-g 10 hours ago

link

Thanks. Just read the GotW?.

http://herbsutter.com/gotw/_102/

reply

--

http://www.stanford.edu/class/ee380/Abstracts/100428-pike-stanford.pdf

---

http://www.informit.com/articles/article.aspx?p=1623555

---

" C++ POD Member Handling Email ThisBlogThis?!Share to TwitterShare? to FacebookShare? to Pinterest

I always mess up the initialization of plain old data fields in C++. Always. Maybe by writing it up, I'll finally get it right.

Plain Old Data is essentially anything a regular C compiler could compile. That is:

    integer and floating point numbers (including bool, though it isn't in C)
    enums
    pointers, including pointers to objects and pointers to functions
    some aggregate data structures (structs, unions, and classes)

A struct, union, or class is treated as plain old data if it has only the default constructor and destructor, has no protected or private member variables, does not inherit from a base class, and has no virtual functions. I suspect most C++ programmers have an intuitive feel for when a class behaves like an object and when its just a collection of data. That intuition is pretty good in this case.

The default constructor for plain old data leaves it uninitialized. An explicit constructor sets it to zero. Code Result

class Foo { public: Foo() {} int a_; };

	Result: a_ is uninitialized.

class Foo { public: Foo() : a_() {} int a_; };

	Result: the member corresponding to a_ is zeroed.Were it a structure, the entire thing would be zero.

People are often confused by the first point, that member POD fields are left uninitialized unless specifically listed in the initializer list. This is not the same as for member objects, which call the default constructor. Making this even more confusing, when a process starts up any pages it gets from the OS will be zeroed out to prevent information leakage. So if you look at the first few objects allocated, there is a better than average chance that all of the member variables will be zero. Unfortunately once the process has run for a while and dirtied some of its own pages, it will start getting objects where the POD variables contain junk.

Struct initializers

Putting a POD struct in the initializer list results in zeroing the struct. If the struct needs to contain non-zero data, C++0x adds a useful capability:

struct bar { int y; int z; };

class Foo { public: Foo() : b_({1, 2}) {} struct bar b_; };

Recent versions of gcc implement this handling, though a warning will be issued unless the -std=c++0x or -std=gnu++0x command line flag is given. Labels: C Programming " -- http://codingrelic.geekhold.com/2011/01/c-pod-member-handling.html


Jweb_Guru 3 days ago

link

...

However, I cannot agree with you .... that you have to be an "idiot" to do memory-unsafe things in C++11. Someone at Yandex recently did a presentation about Rust [1] in which they pointed to a bit of (completely idiomatic!) C++11 code that caused undefined behavior. The audience, full of seasoned C++ and Java developers, was asked to identify the problem. Not one of them could point to what was causing it (the compiler certainly didn't). The next slide demonstrated how Rust's compiler statically prevented this issue. The issue could have taken weeks to surface and days to track down, and the C++ compiler simply didn't have enough information to determine that it was a problem. This is something that happens over and over to anyone using C++, in any application, not just security-critical ones.

I'm not saying C++11 doesn't improve the situation, because it does--it would be disingenuous to say otherwise. But it's equally disingenuous to imply that C++11 makes memory management straightforward or safe. It does not.

[1] http://habrahabr.ru/company/yandex/blog/235789/ (note: the presentation and site are in Russian).

reply

dbaupp 3 days ago

link

The example:

  std::string get_url() { 
      return "http://yandex.ru";
  }
  string_view get_scheme_from_url(string_view url) {
      unsigned colon = url.find(':');
      return url.substr(0, colon);
  }
  int main() {
      auto scheme = get_scheme_from_url(get_url());
      std::cout << scheme << "n";
      return 0;
  }

reply

ufo 3 days ago

link

Can you say what is the problem here? What is a string_view?

reply

dbaupp 3 days ago

link

A non-owning pointer into string memory owned by someone else (effectively a reference into some string). AIUI, the problem is the temporary string returned by get_url() is deallocated immediately after the get_scheme_from_url call, meaning that the string_view reference `scheme` is left dangling.

reply


dbaupp 3 days ago

link

There's more to memory-unsafety than raw pointers; all of these are problems even in the most modern C++ versions:

And there's more to memory safety than security critical applications. Rust means you spend a little more time fighting the compiler, but a lot less time fighting the debugger and a lot less time trying to reproduce heisenbugs caused by data races/undefined behaviour.

Of course, the library/tool support is indisputably in C++'s favour.

> if you're an idiot you can shoot yourself in the face

If you're a human you will shoot yourself in the face. It just takes far too much brain power to write correct C++ always (a single mistake leads to brokenness), especially in a team where there can be implicit knowledge about how an API works/should work that may not be correctly transferred between people.

reply

---

jroesch 3 days ago

link

I'm not sure in what world writing C++11 is "very straight forward ... safe and clean". You can easily write unsafe code without thinking about it. For example one can write a function that lends out a reference or pointer to memory that may or may not exist after the call exits, and this is impossible in Rust.

reply

---

BruceIV? 3 days ago

link

C++11 is still C++ though. I've been writing pretty much exclusively C++11 for the last year, and, while they've added a lot of very nice features and I find it painful to go back to C++03, it's still a huge language with lots of hoary edge cases and everything and the kitchen sink built in (now with rvalue reference and move semantics for extra verbosity!).

I haven't touched Rust since 0.7 (where I abandoned it after filing two bugs on the project before I even got argument parsing working), but it's the most promising of the new batch of languages in my mind, and I have some side projects in mind I'd like to try when 1.0 comes out.

reply

pcwalton 3 days ago

link

Rust is memory-safe; C++11 is not.

reply

---

" Where is Rust Positioned?

The three languages where I do most of my work in are Python, C and C++. To C++ I have a very ambivalent relationship because I never quite know which part of the language I should use. C is straightforward because the language is tiny. C++ on the other hand has all of those features where you need to pick yourself a subset that you can use and it's almost guaranteed that someone else picks a different one. The worst part there is that you can get into really holy wars about what you should be doing. I have a huge hatred towards both the STL and boost and that has existed even before I worked in the games industry. However every time the topic comes up there is at least someone who tells me I'm wrong and don't understand the language.

Rust for me fits where I use Python, C and C++ but it fills that spot in very different categories. Python I use as language for writing small tools as well as large scale server software. Python there works well for me primarily because the ecosystem is large and when it breaks it's a super straightforward thing to debug. It also keeps stays running and can report if things go wrong.

However one interesting thing about Python is that unlike many other dynamic languages, Python feels very predictable. For me this is largely because I am a lot less dependent on the garbage collector that in many other languages. The reason for this is that Python for me means CPython and CPython means refcounting. I'm the guy who will go through your Python codebase and break up cycles by introducing weak references. Who will put a refcount check before and after requests to make sure we're not building up cycles. Why? Because I like when you can reason about what the system is doing. I'm not crazy and will disable the cycle collector but I want it to be predictable.

Sure, Python is slow, Python has really bad concurrency support, the interpreter is quite weak and it really feels like it should work differently, but it does not cause me big problems. I can start it and it will still be there and running when I come back a month afterwards.

Rust is in your face with memory and data. It's very much like C and C++. However unlike C and C++ it feels more like you're programming with Python from the API point of view because of the type inference and because the API of the standard library was clearly written with programmer satisfaction in mind. " -- http://lucumr.pocoo.org/2014/10/1/a-fresh-look-at-rust/

---

cageface 21 hours ago

link

I have a huge hatred towards both the STL and boost and that has existed even before I worked in the games industry.

I really don't understand why STL gets so little love. It's a little lean on features maybe but in my experience it just works, and it's fast. Once you get your head around the iterator concept it's pretty simple to use. And with lambdas in C++ I can write code that's almost as concise as Ruby or Scala.

Any strongly-typed, flexible collection & algorithm library is going to be complex and require a learning curve.

reply

saucetenuto 8 hours ago

link

Lambdas in C++ are pretty new. Most of us who used std::algorithm had to write our own functor structs and do the variable capture by hand. Except that typically we didn't, because at that point a for loop is more readable. I think that's the essential objection to the STL: it's a library built around functional programming and not OO, in a language built around OO and not functional programming.

And of course there are a bunch of small dumb things in it. Why do we have make_heap() and friends instead of a heap type? Why does binary_search() return a bool instead of an iterator? Why didn't we get any hash tables until like 2010? Who thought the vector<bool> specialization was a good idea, and why didn't they benchmark it first?

The STL is a weird mix of brilliant, visionary API design and abject failure. Because of C++'s many limitations, the fail-y parts are the parts that most people are most familiar with. C++11 has done an incredible amount to turn that around, but at this point, for me, it's too late: I'd rather have a new language and new library, informed by C++'s successes without being bound to its mistakes.

reply

stormbrew 21 hours ago

link

In my experience the people who have strongly negative opinions specifically about the STL have it rooted in one of these two things:

Not to say there aren't other reasons people dislike it, but these are big ones.

reply

cageface 21 hours ago

link

Probably true. I wasn't much of a fan either when I first used it in 1996. It was extremely verbose, slow to compile, and tended to generate compilation error messages that filled the screen.

But the experience of using the STL today with the niceties of C++11 and a good compiler like Clang is vastly better. I can now write code almost as concise as Ruby that runs 100x faster, without usually having to worry about memory management. I avoid using the streams stuff though. That chunk of the library could use a serious overhaul.

I'm rooting for Rust because it's designed to address the problem spaces I care about most but C++ has improved by leaps and bounds in the last few years.

reply

antiuniverse 19 hours ago

link

I really don't understand why STL gets so little love.

Well, in light of the fact that the author makes reference to his game industry background, you may find interesting the perspectives given in this paper: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n227...

And partial source code for the library described in the paper: https://github.com/paulhodge/EASTL

reply

wisienkas 8 hours ago

link

Started using rust just this week.

Used more hours than ever expected on it. Simple put you'll fall in love with the compiler, because it point out so well your mistakes.

Another thing to note is that it greatly encourage you to fix your warnings too. which for me coming from java and php world isn't something you'd give much thought.

reply

kibwen 8 hours ago

link

I agree about the warnings. Normal Rust code is already so strict that a lot of the warnings that you'd get from other languages are already compiler errors, which means that issues that are merely good style (e.g. declaring a variable as mutable when you never actually mutate it) can spit out warnings without overwhelming coders and causing them to lapse into "I've already got 200 pages of warnings so screw this" apathy. It's a fine line though, and something we have to remain mindful of as we add more warnings by default.

reply

---

http://goldns.ru/cppmap-2012.png

---