
Elements of Modern C++ Style - rsaarelm
http://herbsutter.com/elements-of-modern-c-style/
======
obiterdictum
We have just started using some C++11 features, and with new features come new
traps and potential complexities, as you'd expect with C++.

A few examples:

1\. Implicit lambdas ("[=]") capture "this" pointer for data members, if you
capture a shared pointer and let the lambda object leave the scope, the shared
pointer won't be copied (<http://stackoverflow.com/q/7764564/23643>), which
may create unpleasant results, like code blowing up in your face.

2\. Overuse of "auto" (not exclusive to C++) may make the code harder to read,
especially if storing a result returned from a function. You can't tell if the
return value is a smart pointer or a raw pointer, value or a reference, so you
can't figure ownership semantics just by looking at the local code.

3\. Move constructors/assignment operators are a bit of a black magic,
especially with regard to suppressing default implementation
(<http://mmocny.wordpress.com/2010/12/09/implicit-move-wont-go>) and exception
safety (<http://cpp-next.com/archive/2009/10/exceptionally-moving>). I would
refrain from using it, until I fully understand it.

With that said, most of C++11 is a welcome change and makes C++ more pleasant
to write, but, as always, you have to have your guard up and use new features
judiciously.

~~~
ajross
C++ always seems to lead to traps. In point #2, you're obviously right about
the micro-coding/readability point. But the premise is kind of scary: you're
dealing with a code base where the ownership semantics of an object are
captured only by a function return type? Yikes. That's a framework issue: if
everyone working on the source isn't 100% sure what that return means, you're
guaranteed to get bugs with or without auto. Non-trivial
ownership/allocation/copy semantics (i.e. anything other than "on the stack"
or "operator new") are deep C++ voodoo, not something you worry about in
passing as a readability thing.

~~~
jemfinch
At least you _can_ express ownership semantics in C++ code, using constructs
like `unique_ptr`, `scoped_ptr`, and `shared_ptr`. In a garbage collected
language, _nothing_ expresses ownership, and so while you not be at risk of
memory leaks, you're still vulnerable to all the other bugs that come with
aliasing mutable objects.

The "framework issue" you describe is solved precisely by specifying ownership
semantics in terms of smart pointer return values. The way everyone becomes
"100% sure what that return means" is by whether it returns a `unique_ptr` or
a `shared_ptr`. The OP is simply complaining that `auto` takes away that
_local_ information on ownership.

`operator new()` is only trivial by virtue of _not specifying anything at all_
about ownership. `scoped_ptr` and `shared_ptr` and `unique_ptr` are each
specifying different, more restricted, but still _trivial_ ownership
semantics. They aren't "deep C++ voodoo" in the least. Your post smacks of
someone who doesn't actually write C++ for a living.

~~~
cpeterso
I wish C++11 added syntactic sugar for the smart pointer classes like
scoped_ptr, shared_ptr, and unique_ptr. I would rather see new operators (like
Microsoft C++/CLI's _^_ and _%_ ) than even more templated code. Compare
something like:

    
    
      int^ foo(int% bar);
    

versus:

    
    
      std::unique_ptr<int> foo(std::shared_ptr<int> bar);
    

Smart pointers have long been available in boost and are required for writing
safe code, but they make code unreadable (even after typedefs).

~~~
pyrtsa
I don't think introducing more syntax to the language for a feature that
ultimately is a library solution, is a sustainable way to go.

But if you really need a compact notation for smart pointers, you'll get
pretty close by using template aliases, e.g.

    
    
        template <typename T> using up = std::unique_ptr<T>;
        template <typename T> using sp = std::shared_ptr<T>;
        // ...
        up<int> foo(sp<int> bar) {
            return bar ? up<int>(new int(*bar)) : nullptr;
        }

~~~
thwest
Oh C++11 has template typedefs? Time to migrate my project.

------
forrestthewoods
When I read articles like this I think of a quote from Carmack.

"The Escalation programmers come from a completely different background, and
the codebase is all STL this, boost that, fill-up-the-property list, dispatch
the event, and delegate that. I had been harboring some suspicions that our
big codebases might benefit from the application of some more of the various
“modern” C++ design patterns, despite seeing other large game codebases suffer
under them. I have since recanted that suspicion."
([http://www.bethblog.com/index.php/2010/10/29/john-carmack-
di...](http://www.bethblog.com/index.php/2010/10/29/john-carmack-discusses-
rage-on-iphoneipadipod-touch/))

The rage in the game dev community these days is all about highly cache aware
Data Oriented Design (DOD) over OOP. Curiously there aren't a lot of DOD
discussions or articles on HN.

~~~
Chris_Newton
> Curiously there aren't a lot of DOD discussions or articles on HN.

How much is there to say, really, once you've got the basic idea?

OOP has always emphasized single objects. Part of that emphasis is that data
is grouped by object rather than by field.

For some applications, this style can work well. GUIs are the canonical
example.

However, if speed really matters, a focus on individual objects is rarely
helpful, because it doesn't support typical data access patterns where
algorithms probably want to work with one field for many objects rather than
many fields for the same object.

This doesn't just matter for games. If you're working on any kind of
mathematical code using large matrices, something as simple as choosing row-
major vs. column-major ordering appropriately can make a very noticeable
difference to performance on modern hardware with several layers of cache.

One of the nicer things about C++ is that while it supports OOP (at least in
the variation that has become most popular) it doesn't try to shoe-horn
everything into being an object and is quite happy for you to worry about your
own memory layouts if you want to.

Once you've understood that basic point, there isn't really much else to know
about Data Oriented Design. It seems like one of those ideas that has been
capitalised to make it seem more important than it really is. If no-one had
popularised OOP, despite its fundamental flaws in this respect, perhaps we
would have just called the DOD approach "common sense"...

~~~
forrestthewoods
I think the types of DOD being discussed in the great twitter wars are far
more complex than common sense.

[http://macton.smugmug.com/gallery/8936708_T6zQX/1/593426709_...](http://macton.smugmug.com/gallery/8936708_T6zQX/1/593426709_ZX4pZ#593426709_ZX4pZ)

~~~
Chris_Newton
I remember when that first did the rounds a few years ago...

The thing is, while it's interesting seeing the potential trouble spots Acton
highlighted, he didn't actually show a better way of doing any of it. As
someone who has also done his fair share of low-level/high-performance
programming in C++, I would take some convincing that the result isn't going
to be somewhat faster but effectively write-only code. That might be OK if you
know your target platforms well enough to count on those micro-optimisations
not being premature _and_ you know no-one is going to care about maintaining
your code for very long, which is not entirely unrealistic in the games
industry but doesn't apply to much else.

However, I think a lot of the ideas on those "slides" go beyond Data Oriented
Design as the term has come to be used, and into general low-level,
architecture-specific optimisations. There's nothing wrong with exploring the
latter, of course, but I'm not sure it's helpful to conflate very fine-
grained, platform-specific, relatively localised adjustments with a high-level
view of how to group multiple properties on a set of objects in memory, or
with the more general principle of transforming your data in advance into some
format that lends itself to the kind of processing you want to do.

(None of which is to say that articles on how to do that sort of low-level
optimisation on popular platforms wouldn't be interesting. I'm just suggesting
that they would probably have to go some way beyond what is commonly called
DOD today before they were likely to get interesting.)

------
cageface
I've been using a lot of these new features in XCode 4 and my code is already
_much_ cleaner and more readable. Modern C++ really is a pleasure to use and I
love writing code that's this high level but still smoking fast.

~~~
rayiner
Are you kidding? The syntax is still inscrutable and the template system is
shit. It's all slightly less shitty than it used to be:

binder2nd< greater<int> > x = bind2nd( greater<int>(), 42 );

but IMHO C++ jumped the shark in 1996 or so.

~~~
cageface
While people are ranting about C++'s warts I'm having a great time writing
performant but clean DSP code _and_ getting paid for it. I don't give a shit
if there's some imaginary pristine alternative.

~~~
rayiner
I used to write high-performance embedded C++ code (and get paid for it). I'd
still rather use a JVM language for the general logic and drop down to low-
level C/assembler for the really performance-critical stuff.

The only thing I'd use C++ for these days is where it's minimal runtime
support requirements come in handy (e.g. runtimes for other languages).

~~~
cageface
Sure. I'd use Scala if the situation allows. But these days I'm doing realtime
DSP & OpenGL stuff and I'm very happy I don't have to do this in a language as
low-level as C.

------
pepsi_can
This c++ is very different from the c++ I remember. I'd like to learn more
about modern c++ style and idioms. Can anyone recommend a good text?

~~~
andrewcooke
i have asked here <http://news.ycombinator.com/item?id=3114567> and here
<http://news.ycombinator.com/item?id=3098298> \- so far, nothing wonderful.

~~~
cageface
Unfortunately it's too new. If Scott Meyers updates effective c++ that will be
the one to get.

------
gcv
That looks surprisingly good, and might even improve new projects which have
to use C++. How long until compilers support all this?

~~~
obiterdictum
I'd say by the middle of next year you should be able to use the a lot of the
features portably.

GCC: <http://gcc.gnu.org/projects/cxx0x.html>

Clang: <http://clang.llvm.org/cxx_status.html> (currently down)

MSVC:
[http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.a...](http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx)

Notably lacking in current production versions:

1\. explicit overrides in GCC

2\. lambdas in Clang

3\. Variadic templates, range loop in MSVC

~~~
apaprocki
Sadly, vendor supplied toolchains for other systems are going to lag far
behind. It is not always an option to use GCC/Clang on these boxes. Compilers
like Oracle Studio CC, IBM xlC, and HP aCC, etc. So this is not really the
definition of "portable" I'm used to. I know I can take any C++98 code and
reliably build on any platform/toolchain. It will be a long time before I can
say the same about C++11. Even C99 isn't truly "portable" because Microsoft
refuses to add all C99 features to MSVC.

~~~
nobody31
Microsoft don't ship a C compiler

Adding C99 features to their C++ compiler would be nice be probably not cost
effective for them

~~~
maximilianburke
Sure they do, it's bundled with their C++ compiler. cl.exe will happily turn
on C90 mode and compile files as C, not C++, if you supply the /TC option or
your source files have the .c extension.

------
pandaman
Auto everywhere is pretty dangerous despite what Mr. Sutter says. Many C++
libraries rely on type conversion (in high performance math it's very common
however you can find it as close as the STL's vector<bool>). Whenever you use
your own memory allocator and/or care about performance (and this is whenever
you are writing high performance/high reliability code) library smart pointers
are pretty useless too. Other things are not as controversial as these two,
but don't really define the modern C++. Herb should have read his friend's,
Anderi Alexandrescu's, book from ten years ago to get a hint of what modern
C++ looks like :) (I know he has read it. I guess he is just trying to pimp
C++ to Java/PHP/Python/etc developers).

~~~
phaedrus
He's not advocating "auto everywhere", he just said it will make the STL
algorithms easier to use (which it will). The other benefit of auto is for
generic code (code in templates) where you might not necessarily _know_ what
the return type is, or at least where the return type is going to be very
complicated to specify. (This last is the same reason C# added var at the same
time as they added LINQ - the return types of LINQ expressions would be
difficult to specify manually.)

~~~
pandaman
He says "Use C++11 auto wherever possible." Nobody argues auto and decltype is
necessary for generic code but this not what Sutter's writing about. In fact
he does not have a single word like "generic" or "template" in his entire
article. Which alone should be a good indication this has nothing to do with
the modern C++ style unlike Alexandrescu's book with the similar name.

------
X-Istence
The only issue I have ran into is that some of these newer features are not
yet available in compilers that are shipping with OS's we are deploying on, so
I HAVE to continue writing to C++98 since installing a new compiler/libraries
is a no go (if it is not vendor supported, can't do it, thank you US gov't
rules!).

It will take some time for the compilers and their libc++ libraries to move
forward and have older versions of OS's replaced by ones that do support it.

That being said, wherever I can (in personal projects) I will slowly start
adapting and using the new features...

------
kleiba
I don't know a lot of C++, but the examples that demonstrate how C++11
compares to C++98 look like a vast improvement. Until you come down to this
monster:

    
    
        auto i = find_if( begin(v), end(v), [=](int i) { return i > x && i < y; } );
    

This is the _improved_ version by the way, but I'm not sure if a loop wouldn't
be more readable for such a straight-forward problem. Plus I can't help but
think that C++ will probably never win a beauty contest.

~~~
CountHackulus
I don't see what the problem is here, this is very readable to me. You want to
find between the beginning and end of a list called v, for a value between y <
i < x. Admittedly the condition in the lambda could be better written, and the
results should probably be called something other than i, but it's perfectly
clear what's going on here.

Let's look at the equivalent C++98 loop:

    
    
       int i = -1;
       for(std::vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)
       {
          if(*iter > x && *iter < y)
          {
             i = *iter;
             break;
          }
       }
    

It's not only much more verbose, but the types need to be expressly written,
and what's going on isn't immediately obvious from the function name.

No, C++ will never win a beauty contest (I'd vote for D or Haskell
personally), but it's great for expressibility, and the new C++11 changes make
things more concise.

~~~
kleiba
Agree completely.

When you compare the new code to the C++98 one, it looks like a great
improvement. But isn't that because C++98 simply sucked even more? As you say,
when you compare it to languages like Haskell, even the new C++11 leaves
something to be desired.

------
protomyth
Does anyone have a recommendation for an intro book for experienced
programmers (not C++ programmers) that teaches C++ using a "good" C++11 style?

~~~
16s
Newer books likely have not been written yet. C++ is pretty standardized and
has been for a while. I suggest "Accelerated C++" if you want to learn
idiomatic C++, and then you'll understand (for the most part) how the new 2011
additions work.

------
zurn
Best joke is at the end: "These features [...] make modern C++ the clean, and
safe, and fast language that our industry will continue relying on heavily for
years to come."

------
ericHosick
Will C++ get properties some day (similar to C# properties)?

