Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Writing modern C++ code: how C++ has evolved over the years

Download

Right click “Save as…”

Slides (view online)

Many people think of C++ as the same language they experienced in college or just as “C with classes”, but the C++ language has evolved extensively over the years. In this session, we’ll cover how you can use C++ to write innovative, expressive and beautiful apps that deliver power and performance apps. Join us to see how the newly finished C++0x standard can make writing C++ as productive as many other languages.

このセッション スライドが日本語に翻訳されました。日本語版のファイルをダウンロードするには、こちらをクリックしてください。

For more information, check out this course on Microsoft Virtual Academy:

Follow the Discussion

  • When I take a C++ temperature reading at the place I work, I find that the close to freezing point result is largely because, on Windows at least, C++ is equated in folks minds with COM and referencing counting pain, registry rot and three dozen string representations. As someone who has enjoyed the coffee decade of C# but remains at heart a native chap, I really think Microsoft should put some marketing dollars into separating C++ and COM in the minds of developers. Modern C++ is beautiful, but much of management these days is made up of ex-developers who have flashback episodes to the pre-.NET days of COM and have invested heavily in re-educating themselves and their teams that C++ is a bad choice.
  • MFHMFH

    @dot_tom: It's not really Microsoft's task to teach developers what C++ is, is it? Funnily at my work place nobody thinks C++ == COM and we are still heavily developing with C++ - starting with C++11 features already. Funnily I know nobody that thinks that COM was a bad design - taking it's goals into account - it's not like you have much alternative without an official ABI (and we all know that that's a dream that will never come true…)

     

    @Herb: Thanks for this presentation.

  • Memory safe??? I'm very intrigued. C++ burned me years ago. I would love to see that times have changed.

  • C64C64

    Thanks for this excellent session!

     

     

     

  • AlexAlex

    Awsome session with an awsome speaker. thanks for putting this online for us :)

  • Thanks for this Herb, I really enjoyed it.

    I have a few questions:

    Why do you prefer std::for_each over range-based for? Is it because range-for isn't implemented in VS11 (it's not in the dev preview) or is std::for_each faster because of loop unrolling? Or another reason?

    Instead of boost::noncopyable howcome C++11 defaulted and deleted functions weren't added. I know it would be slightly more verbose, two lines instead of one to disable copy, but I think they are superior. Lack of time?

    P.S binary_search which returns a bool. that made me laugh. lol. Over the years, I wonder how many C++ programmers have rolled their own binary search which returns an iterator? Not the finest moment for the STL!

  • jackjjackj

    "C++ code is more difficult to write than in other languages, but efficient code is a lot easier".

    That is not true. It is trivial to write very efficient code in Fortran, much easier than it is to write efficient code in C++ (e.g. in C++ you need a compiler extension like "restrict" to get what you get for free in Fortran).

  • jackjjackj

    Also, on the "What's Different: At a Glance" slide, on the right hand side Herb writes:

    for_each( begin(vw), end(vw)

    Begin and end are member functions of the vector container, so what you really want to say is:

    for_each( vw.begin(), vw.end()

  • klaimklaim

    Err... no, there are now those two std function, begin() and end() that will take the right member for you with the call context in mind. For example in a const member function, if the container is a member too, begin(vw) will return vw.cbegin() and end(vw) will return vw.cend() that are new too.

    Using begin(vw) and end(vw) makes the code more generic as you don't have to specify wich type of access you need. You can also easily extend any loop written using begin() and end() by writing their specialization for your own types.

    That's why it's recommanded. In one of the slides, Herb uses v.begin() and v.end() and I think that's a typo.

  • @klaim: Yup, that's a typo. I thought I had changed all those. Old habits die hard!

  • BenjaminBenjamin

    @jackj: It's even more generic than klaim claims. It even works with standard c-arrays. So, given 'int arr[10]', begin(arr) will give you 'arr', and end(arr) will give you 'arr + 10'.

  • jackjjackj

    @klaim, @Benjamin: OK, you're both right, I just hadn't seen this before. In my defense, though, Herb uses these new functions 20 minutes into his talk and only explains them 20 minutes later.

    BTW, it's interesting to note that nobody commented on the "C++ is easy to write efficient code in" meme. (And just so nobody repeats the age-old "Fortran is obsolete" bit: Fortran is used in benchmarking all the world's big supercomputers.)

  • That is not true. It is trivial to write very efficient code in Fortran, much easier than it is to write efficient code in C++

    @jackj: Fortran does the world's best job with certain kinds of code that manipulates arrays and doesn't need lots of abstractive flexibility. And those array capabilities are now coming into C++ with C++ AMP and other libraries.

    Fortran is valuable, but it isn't in the same bucket as C and C++ in terms of being a general-purpose language, and especially not with C++ in terms of being a general-purpose language with strong and flexible abstractive power. Fortran rules with arrays -- well, you should add a caveat here that Fortran was even better before Fortran 90 went the wrong way on the aliasing question, but anyway -- but it doesn't have the same rich flexibility and efficiency with classes and especially templates that C++ has.

    As a litmus test to compare C++'s abstraction + efficiency to other languages: 20 years ago, Alex Stepanov wrote STL in C++ not because he started in C++ (he didn't, he started in Ada) or even because he particularly liked C++ (just read his comments about it), but because the only language then available that let him express the genericity and efficiency requirements of the STL was C++...

    ... and 20 years later, it still is. That's telling.

    Don't get me wrong, I love Fortran. If you look at C++ AMP, you'll see array_view<T,Dim> as a central abstraction, and I've said publicly that as we were designing it I kept saying at every other meeting, "the more we flesh this out, the more we're bringing Fortran arrays into C++." I think that's true, and very valuable. Just like we've also already brought in functional languages' lambda functions and Simula's classes and Ada's generics, but in every case with a 100% emphasis on efficiency that has beat out the original languages' versions on at least that criterion. And all those features largely "just work together" in arbitrary combination while remaining efficient with a "don't pay unless you use it" design. That was Bjarne's stroke of genius, and I'm very glad to see C++ continuing with it -- that is exactly what makes C++ the highly relevant language it is today.

    (e.g. in C++ you need a compiler extension like "restrict" to get what you get for free in Fortran).f

    If you mean C++ AMP restrict, I can't think of anything that corresponds to in Fortran. The thing in C++ AMP that corresponds to a Fortran feature is the array_view<T,Dim> library type which basically is bringing Fortran arrays into C++ (see above).

  • jackjjackj

    @hsutter: Wow, what a great response! Thanks for taking the time to write this.

    I completely agree that the expressive power of C++ is superior to that of Fortran. Also, the C++ standard library is much more extensive and therefore more useful than the tiny Fortran library. Similarly, generic programming in C++ is much broader and deeper than what in Fortran seems more like a misnomer. Finally, the C++ community is incredibly bigger and therefore book availability and compiler support is much more impressive (witness C++11's features already in Visual C++ and in GCC and compare with the lack of support for Fortran... 2003!).

    All I meant to say is that Fortran is easy to write simple and efficient code in, nothing more. For any reasonable complex piece of code that many programmers need to work on I'd pick C++ any day of the week.

    PS: Regarding restrict, I was referring to C99's restrict, which helps with pointer aliasing. In C++ one can only get this as a compiler extension -- numerical people like me would love to have it as part of a future standard! (The C++ AMP restrict is a different story and seems perfectly legitimate to me.)

    PPS: Great talk, by the way!

  • Geddy Lee pushed to the back of a vector. Now I've seen everything...  Big Smile

    Is there a table anywhere that lists all the classes/algorithms/etc. that have been added to the std:: library?

  • felix9felix9 the cat that walked by itself

    Super awesome !

  • mdkmdk

    Great presentation!

  • BoyGeniusBoyGenius

    I think I may start C++ development again just because some aspects really are different from the C++ I have known. However, I would have loved if more of the C++11 stuff would make it into the next release of VS :S

  • Why do you prefer std::for_each over range-based for? Is it because range-for isn't implemented in VS11 (it's not in the dev preview) or is std::for_each faster because of loop unrolling? Or another reason?

    @Ricky65: Range-for isn't in VS11, but that's not the main reason I choose to teach for_each. Briefly, range-for is the only algorithm C++11 actually wired into the language itself, and there are lots of other useful algorithms -- in the STL, in existing libraries, and in any new function template you care to write this afternoon that takes an iterator range -- all of which can now be used just about as if they were new built-in loops baked into the language. In the Algorithms section, for example, I mention for_each, find_if and sort/*_bound as the bread-and-butter algorithms to reach for; range-for only competes with one of those, and its syntax is only slightly easier.

    My personal opinion is that range-for already has not as much advantage over for_each in the presence of lambdas, and if we'd gone a little further with lambdas there would have been no compelling reason at all to add range-for. In particular, if C++ had added (or in the future adds) range-based STL algorithms and slightly more convenient lambdas -- specifically, if I could write something like "for_each( v, [&]( e ) { ... } );" where "v" means the same as "begin(v), end(v)" and the lambda parameter "(e)" part would automatically deduce the type so you don't have to repeat it again), I don't think we would have bothered to standardize the range-for loop as a language extension because it's barely any better in usability and performance than calling the library algorithm with a lambda. Here's the side-by-side: for( e : v ) { ... } compared to for_each( v, [&](e){ ... }); .

    Even in C++11, STL for_each + lambdas is already pretty close to competitive with range-for -- what I'm looking for beyond that is mostly incremental convenience and when that comes along there'll be little incentive to use the range-for as far as I can tell.

    Instead of boost::noncopyable howcome C++11 defaulted and deleted functions weren't added. I know it would be slightly more verbose, two lines instead of one to disable copy, but I think they are superior. Lack of time?

    Yes, we didn't get to that (as I mention in the first 5 min of the talk, we were shooting for variadic templates and it turns out they didn't quite fit; if we'd known that we'd have done several other smaller things like possibly that).

    However, it wouldn't have changed the advice. Having =delete doesn't change this advice because it doesn't make turning off copying any easier to author, it just gives you compile-time error instead of link-time error when you try to copy a noncopyable object. The code is just as verbose with =delete. Without C++11 =delete you'd write

    class shape {
      // Without =delete: the following four functions are private and undefined
      shape( const shape& );
      shape& operator=( const shape& );
      shape( shape&& );
      shape& operator=( shape&& );
      :::
    };

    and in C++11 this would change to

    class shape {
      // With =delete: the following four functions are turned off
      shape( const shape& ) = delete;
      shape& operator=( const shape& ) = delete;
      shape( shape&& ) = delete;
      shape& operator=( shape&& ) = delete;
      :::
    };

    and in either case it's much simpler to teach people to just write

    class shape : boost:noncopyable {
      :::
    };

    which is better whether or not the compiler supports =delete yet or not.

  • jn99jn99

    On some slide in the middle of the talk (around 30min, topic "Containers") there is an example of a vector of strings and the green description box says "compact, efficient, cache-friendly, prefetcher-friendly.
    The point though is, the exact opposite is true at least in this case. The reason being that all the strings in the vector are not stored in one, compact, cache-friendly blob of data. In contrast, all the strings point to different places in memory (this is true in general; i know about short string optimization), so this is the exact opposite of cache-friendliness. Vector itself is cache-friendly, admitted. But any use of vector with objects in it is not (using default allocators of course).

  • I'm surprised that the range-for, a language extension, made it into the standard when a beautifully composable library extension using for_each was *so* close to being realized.  Just need those polymorphic lambdas [&](auto& e) {...}

  • @jn99: Actually, vector (and array) is all of those things compared to any other container. Briefly, some things to keep in mind:

    1.  vector<T> is always fully compact/contiguous when T is a value type that stores all its state internally.

    2. In particular, vector<string> is indeed fully compact/contiguous except for any contained strings whose length exceeds the small string optimization (SSO) threshold. This depends on the application, of course; in general use studies in several decades have shown that "most strings are short in most applications," but there's a range where in some apps the majority are long (e.g., app that uses strings mainly to bind to SQL varchar(100)) and in others nearly all are short (e.g., app that uses strings mainly for stock symbols).

    3. vector<T*> including the owned T's isn't fully contiguous, of course, but don't forget that: a) any_container<T*> isn't either; and b) vector<T*> still has a contiguity and performance benefit (e.g., still lowest per-element overhead, and it stores the pointers contiguously which means that in many loops the compiler/processor can issue a bunch of memory requests concurrently to fetch the T objects and take a memory latency hit only once, which you can't do in a pointer-chasing data structure).

    So vector<X> and array<X> are always "more" contiguous and cache-friendly than other_container<X>, even when the whole thing isn't fully contiguous.

  • VisitorVisitor

    @hsutter,

    Herb, the feature table on http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx looks very disappointing.
    Furthermore, the apparent preference that Microsoft gives to proprietary extensions (C++ AMP) over standard features brings bad memories of past behaviour (Embrace, Extend, Extinguish).

    Can you please tell us what is the planned target date for full(*) C++11 conformance?

    Thank you.

    (*) "Full" as in "At least as conforming as the current version conforms to C++03".

  • AndreyAndrey

    @hsutter I think that current situation with type inference and functions is very serious design flaw. for_each syntax is much better then for syntax, but still it is ugly, because lambda notation should be simpler, compiler should be able to deduce types of args of lambda by himself. Example: (formatted version here: http://pastebin.com/mY3f6njM)


    template<class T>
    void f(T t)
    {
    cout << t;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
    std::vector<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    f(a.begin());
    //Works
    for_each(begin(a), end(a), f<int>);
    //Doesn't!
    for_each(begin(a), end(a), f);
    //Works
    for_each(begin(a), end(a), [](int x) { cout << x; });
    //Doesn't!
    for_each(begin(a), end(a), [](auto x) { cout << x; });
    }

    I really can't see a problem here. begin and end returns the same, why can't compiler try to apply thier return type as template parameter of f or lambda? It is implemented in C# and works wonderful making lambdas very clean there.

    Second thing that I think is ugly is that you have to declare variables that makes a clojure:

    int y = 5;
    for_each(begin(a), end(a), [y](int x) { std::cout << x*y; });

    Again, why compiler can't deduce it?

    And last thing. C++ has only one possible body for lambda: statement(s) and this is not cool, if lambda consists of one expression you should be able to write it as expression, without return and brackets (optionally). I think that C#'s lambas are the best implementation in imperative world, even Java version is officially borrowed from C#. I think it is time for C++ to learn something from C#!

  • Thank you for replying to my questions, Herb.

    I agree that range-for doesn't have much of an advantage over for_each in the presence of lambdas. However, I'm glad range-for was standardized. I agree that range-based STL algorithms and polymorphic lambdas make range-for almost redundant, but they are not standard at the moment. range-for has automatic type deduction today (if it were implemented). Also it is possible to break and continue with range-for which I can't do with for_each, even with range-based STL and polymorphic lambdas.

    Personally, using std::for_each with a lambda in VS 2010 is sufficient for most of my needs. I have created my own for_each_n algorithm (I'd love to see something like it in the standard btw) for when I want to only do something with the first, say 10 elements in a range. I couldn't do that with range-for.

    You mention that if range-based STL algorithms and polymorphic lambdas were added there would be "little incentive" to use range-for. I agree with you but I still think range-for will be popular as some programmers have the perception that built-in language facilities are superior to library alternatives.

    Regarding non-copyable classes, although boost::noncopyable may be easier to use and teach I still feel it is only a partial solution. The problem being that using a base class with private copy constructor and assignment operators makes a class non-POD. I think boost::noncopyable using defaulted and deleted functions would combine the best of both.

    Something like:

    class noncopyable

    {

    public:

    noncopyable() = default;

    noncopyable(noncopyable const &) = delete;

    noncopyable & operator=(noncopyable const &) = delete;

    };

     

  • Thanks for this awesome talk. Very instructive and pleasant to watch. Hope you would do other talks like that.

    C++ has really changed in the last years, I didn't notice how deeply, although I use it very often: I couldn't see the forest for the trees. Thanks for pointing this out.

  • Great presentation. And some funny, yet true remarks on C++ (garbage collection, auto pointer, etc.).

  • This is all very exciting! I really hope that the new standard and new compilers encourage authors and publishers to publish some new books based upon these modern practices. It is very hard to find a good C++ book these days and even harder to find one consumable by language novices.

    So far it looks like as though publishers are just tagging on a C++11 chapter at the end of books that have been recycled since the first standard. This C-with-classes view persists and it really is time for a re-evaluation of the way C++ is approached - this new standard is a perfect opportunity.

  • Excellent talk! I've been promoting C++ resource management for years; but with C++11's move semantics there's no longer any excuse for unsafe practices that plagued old C++. My content-index team at Microsoft in the 90's never used delete, except in the lowest level libraries. We were the only group working on Cairo that had zero memory leaks.

  • yuriksyuriks

    Any idea if variadics or any new features will be coming in a service pack? Or will we have to wait until VC12 for them?

  • Ruslan BalaganskyRuslan Balagansky

    Great presentation.

    Personally, I think that range-based for is worthwhile syntactic sugar.

    It may be only a small hop away from for_each with lambdas, but it is, I think, by far the most common use case. By Amdahl's law, optimizing for this use case yields considerable total value.

    The fact is that, while lambdas are conceptually elegant, they are still syntactically ugly:

    for (int &i : v) {
    ++i;
    }

    versus

    // using Herb's proposed overload with implicit range
    for_each(v, [](int &i) {
    ++i;
    });

    Examining that, notice there are roughly twice as many enclosing symbols: (), [], (), {} rather than just (), {}.

    Also, the () encloses {}, which can be jarring for those that aren't used to reading such syntax.

    Lastly for_each is a function, where for is a control flow construct. It has a slightly different 'feel', even though it should be just about equivalent in a decent compiler. This function is also in a namespace, which actually means that, unless you are comfortable using 'using', it would look like this:

    std::for_each(v, [](int &i) {
    ++i;
    });

    That looks even less like your ordinary, beloved for loop.

  • JedrekJedrek

    Because Microsoft has started to improve C++ in general maybe it will be possible to add support for "long double" to Visual Studio C++ Compiler. At this moment "double" and "long double" are the same types in VS. Because of that for high precision numerical calculations I have to use non-Microsoft C++ compilers (g++ or Intel C++ Compiler).
    Microsoft removed the support for "long double" in Visual Studio after the ".net revolution". Maybe it is a time to fix that?

    "long double" is a part or C++ standard.

  • JonJon

    What are the performance implications of:
    1) Using a lambda instead of a handwritten loop? Does the compiler inline the function?
    2) Using a container of shared_ptr which implies atomic reference counts and therefore memory barriers.

    One concern I have with "auto" is that the code reader (not just the compiler) has to deduct the type. Might make reading code or deducing the interface and semantics of a variable a little harder.

    @hsutter: Re "vector<X> and array<X> are always "more" contiguous and cache-friendly than other_container<X>".
    I've found that when needing to insert elements in the middle of a collection, the cost of binary search and memcpy (used by vector) exceeded the cost of doing a linear search through a std::list and inserting the element. Of course this depends on the situation, but it's always worth profiling.

  • ClaudioJrClaudioJr

    @hsutter,
    Will it be possible to write desktop applications using XAML for handling UI code?

  • Lefteris KalamarasLefteris Kalamaras

    My gripe isn't particularly with C++ and its advances, as it is with those advances breaking functionality that is a time saver for developers. We are so used to "Edit & Continue" functionality in all our C++ projects, we can't do without it. We were very happy to also see lambda expressions introduced in Visual Studio 2010 (and extended in 2011 preview) but unfortunately, the E&C functionality is removed whenever our code contains lambdas as the debugger can't cope with it.

    Any ideas if/when that might be corrected? Until then, we're forced NOT to use lambdas as it seriously hampers our efficiency and productivity.

  • JohanJohan

    I just want to thank you for this speech and show my support! Like many others, I'm very excited about the bright-looking future for C++.

  • ShigiShigi

    What about Qt containers and Qt features?
    I think Qt has a better optimization and is maybe quite faster, has a many features such as implicit sharing and so on...
    Should C++ programmers use it as default?

  • MirceaMircea

    I wonder if the code in slide 9 (or around 0:27 in the video) which does "children.push_back( new node(…) );" is wrong.

    First of all I'm not sure if it compiles because children is vector<unique_ptr<node>> and unique_ptr<node> would have an explicit constructor so no conversion from new node().

    Second if it works isn't this living dangerously on the cliff unnecesarily: won't this technique leak memory if new succeeds but push_back fails when the vector is resized?

  • John WJohn W

    In the part about how std::vector uses move semantics to not realocate itself. Doesn't it destroys cache locality? Bjarne Stroustroup showed how std::vector beats std::list at inserting in middle thanks to cache locality. It would be strange if because of move semantics the std::vector becomes a strange std::list. Maybe i misunderstood something.

  • David IDavid I

    Love the new direction of C++11 and how it streamlines a lot of daily tasks.

    I've always tried to favor generic algorithms over manual loops when possible but I've found it difficult to make my co-workers appreciate them for one fundamental reason: debugging/tracing.

    Even with lambdas, it appears like there's a little decentralized hoop jumping (into for_each and then into the body of the lambda). I don't mind adapting to this style of debugging at all, but my co-workers do, so much that the seniors have, for the most part, forbidden generic algorithms in favor of more dumbed down loops unless it would be very hard to avoid (std::sort, e.g., but not find_if or for_each).

    I'm not sure what arguments I can present against that to try to win them over, but I was wondering as a sort of question (or possibly suggestion otherwise) if it might be possible for the debugger to avoid stepping into standard library code. That would then allow us to get the sort of centralized tracing behavior, combined with lambdas, that would allow me to get my co-workers to finally accept this.

    Finally, I was wondering more about the module boundary issues associated with C++11's pointer types. I'd love to be able to use unique_ptr to implement the pimpl idiom for an API, but what if someone is building that code with, say, Intel C++ compiler or mingw (assuming they catch up to versions of GCC supporting C++11)? One of the disappointing parts of C++ for me has always been the inability to use types like std::vector across module boundaries for clients using different compilers/settings because of the binary incompatibility between two different standard library implementations. Is this something that C++11 addresses at all?

  • David IDavid I

    "I'd love to be able to use unique_ptr to implement the pimpl idiom for an API, but what if someone is building that code[...]"

    Apologies, I meant to say, "what if someone is dynamically linking to that code against the same header".

    Our product is heavily driven by our SDK which we use both internally and for third parties, so we're limited to portable types in most cases. Flattening to C code or building our own types (our own STL-compliant vector, shared_ptr, e.g.) is what we've done for the most part, even though our clients are mostly using C++. I'd much rather prefer to simply use the standard types, but our API compatibility with different compilers and vendors has always been a limiting factor.

  • Vlad KudelinVlad Kudelin

    Why such terrible video quality?

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.