C++14 Style 9/13/2014 Herb Sutter

Herb Sutter

C A Complexity Anonymous

A 12-step program for good people attempting to recover from complexity addiction

 2014 Herb Sutter except material otherwise referenced. 1 C++14 Style 9/13/2014 Herb Sutter

C++ developers (~3M)

libstdc++ developers (~30) + libc++ developers (~5-7) + Boost developers (~300?) + ISO WG21 attenders (~300?)

 2014 Herb Sutter except material otherwise referenced. 2 C++14 Style 9/13/2014 Herb Sutter

Occurrences of “&&” in Bjarne’s 90-min Tue keynote? 0

Value of modern C++’s simple usable defaults? Priceless

 “What should every C++ programmer be expected to know?”  For years, there has not been a single source to point to.

 Now there is. In 180 pages you can read on a long plane flight.  Recommend it heavily!  Also a demonstration that modern C++ is simpler to teach and explain.

 2014 Herb Sutter except material otherwise referenced. 3 C++14 Style 9/13/2014 Herb Sutter

 This talk focuses on defaults, basic styles and idioms in modern C++.  “Default” != “don’t think.”  “Default” == “don’t overthink.” Esp. don’t optimize prematurely.

 These reinforce (not compete with) the “fundamentals.”  “Write for clarity and correctness first.”  “Avoid premature optimization.” By default, prefer clear over optimal.  “Avoid premature pessimization.” Prefer faster when equally clear.

why do this for( auto i = begin(c); i != end(c); ++i ) { … use(*i); … }

when you can do this for( auto& e : c ) { … use(e); … }

and soon this for( e : c ) { … use(e); … }

 2014 Herb Sutter except material otherwise referenced. 4 C++14 Style 9/13/2014 Herb Sutter

wait, what?

 C++98:  Modern C++: widget* factory(); unique_ptr factory(); void caller() { void caller() { widget* w = factory(); auto w = factory(); gadget* g = new gadget(); auto g = make_unique(); use( *w, *g ); use( *w, *g ); delete g; } delete w; } red  now “mostly wrong” 

 Don’t use owning *,  For “new”, use make_unique by default, new or delete. make_shared if it will be shared.  Except: Encapsulated inside  the implementation of low- For “delete”, write nothing. level data structures.

 2014 Herb Sutter except material otherwise referenced. 5 C++14 Style 9/13/2014 Herb Sutter

NB: important qualifier

 C++98:  C++14: widget* factory(); unique_ptr factory(); void caller() { void caller() { widget* w = factory(); auto w = factory(); gadget* g = new gadget(); auto g = make_unique(); use( *w, *g ); use( *w, *g ); delete g; } delete w; } red  now “mostly wrong” 

 Don’t use owning *,  For “new”, use make_unique by default, new or delete. make_shared if it will be shared .  Except: Encapsulated inside  the implementation of low- For “delete”, write nothing. level data structures.

 C++98 “Classic”:  Modern C++ “Still Classic”: void f( widget& w ) { // if required void f( widget& w ) { // if required use(w); use(w); } } void g( widget* w ) { // if optional void g( widget* w ) { // if optional if(w) use(*w); if(w) use(*w); } } auto upw = make_unique(); … f( *upw );  auto spw = make_shared(); * and & FTW … (More on parameter passing coming later…) g( spw.get() );

 2014 Herb Sutter except material otherwise referenced. 6 C++14 Style 9/13/2014 Herb Sutter

 Antipattern #1: Parameters  Antipattern #2: Loops (Note: Any refcounted pointer type.) (Note: Any refcounted pointer type.) void f( refcnt_ptr& w ) { refcnt_ptr w = …; use(*w); for( auto& e: baz ) { } // ? auto w2 = w; void f( refcnt_ptr w ) { use(w2,*w2,w,*w,whatever); use(*w); } // ?!?! } // ?!?!?!?!

Example (thanks Andrei): In late 2013, RocksDB changed from pass-by-value shared_ptr to pass-*/&. QPS improved 4 (100K to 400K) in one benchmark. http://tinyurl.com/gotw91-example

FAQ: Parameters — See GotW #91 (tinyurl.com/gotw91) Refcounted smart pointers are about managing the owned object’s lifetime. Copy/assign one only when you intend to manipulate the owned object’s lifetime. Any “smart pointers (or std::vectors) are slow” performance claims based on code that copies/assigns smart pointers (or std::vectors) – including passing by value or copying/assigning in loops – when copies are not needed are fundamentally flawed.

Yes, this applies to your refcounted smart pointer: • shared_ptr (Boost, TR1, std::) • retain/release (Objective-C ARC, Clang 3.5) • AddRef/Release (COM and WinRT, C++/CX ^) • any other refcounting strategy you will ever see

 2014 Herb Sutter except material otherwise referenced. 7 C++14 Style 9/13/2014 Herb Sutter

unique_ptr factory(); // source – produces widget void sink( unique_ptr ); // sink – consumes widget void reseat( unique_ptr& ); // “will” or “might” reseat ptr void thinko( const unique_ptr& ); // usually not what you want

shared_ptr factory(); // source + shared ownership // when you know it will be shared, perhaps by factory itself void share( shared_ptr ); // share – “will” retain refcount void reseat( shared_ptr& ); // “will” or “might” reseat ptr void may_share( const shared_ptr& ); // “might” retain refcount

1. Never pass smart pointers (by value or by reference) unless you actually want to manipulate the pointer  store, change, or let go of a reference.  Prefer passing objects by * or & as usual – just like always.  Else if you do want to manipulate lifetime, great, do it as on previous slide. 2. Express ownership using unique_ptr wherever possible, including when you don’t know whether the object will actually ever be shared.  It’s free = exactly the cost of a raw pointer, by design.  It’s safe = better than a raw pointer, including exception-safe.  It’s declarative = expresses intended uniqueness and source/sink semantics.  It removes many (often most) objects out of the ref counted population. 3. Else use make_shared up front wherever possible, if object will be shared.

 2014 Herb Sutter except material otherwise referenced. 8 C++14 Style 9/13/2014 Herb Sutter

 The reentrancy pitfall (simplified):  “Pin” using unaliased local copy.

// global (static or heap), or aliased local // global (static or heap), or aliased local … shared_ptr g_p … … shared_ptr g_p …

void f( widget& w ) { void f( widget& w ) { g(); g(); use(w); use(w); } } void g() { void g() { g_p = … ; g_p = … ; } }

void my_code() { void my_code() { auto pin = g_p; // 1 ++ for whole tree f( *g_p ); // passing *nonlocal f( *pin ); // ok, *local } // should not pass code review }

 The reentrancy pitfall (simplified):  “Pin” using unaliased local copy.

// global (static or heap), or aliased local // global (static or heap), or aliased local … shared_ptr g_p … … shared_ptr g_p …

void f( widget& w ) { void f( widget& w ) { g(); g(); use(w); use(w); } } void g() { void g() { g_p = … ; g_p = … ; } }

void my_code() { void my_code() { auto pin = g_p; // 1 ++ for whole tree f( *g_p ); // passing *nonlocal f( *pin ); // ok, *local g_p->foo(); // (or nonlocal->) pin->foo(); // ok, local-> } // should not pass code review }

 2014 Herb Sutter except material otherwise referenced. 9 C++14 Style 9/13/2014 Herb Sutter

1. Never pass smart pointers (by value or by reference) unless you actually want to manipulate the pointer  store, change, or let go of a reference.  Prefer passing objects by * or & as usual – just like always. Remember: Take unaliased+local copy at the top of a call tree, don’t pass f(*g_p).  Else if you do want to manipulate lifetime, great, do it as on previous slide. 2. Express ownership using unique_ptr wherever possible, including when you don’t know whether the object will actually ever be shared.  It’s free = exactly the cost of a raw pointer, by design.  It’s safe = better than a raw pointer, including exception-safe.  It’s declarative = expresses intended uniqueness and source/sink semantics.  It removes many (often most) objects out of the ref counted population. 3. Else use make_shared up front wherever possible, if object will be shared.

Don’t use owning raw *, new, or delete any more, except rarely inside the implementation details of low-level data structures. Do use non-owning raw * and &, especially for parameters. Don’t copy/assign refcounted smart pointers, including pass-by-value or in loops, unless you really want the semantics they express: altering .

 2014 Herb Sutter except material otherwise referenced. 10 C++14 Style 9/13/2014 Herb Sutter

 2014 Herb Sutter except material otherwise referenced. 11 C++14 Style 9/13/2014 Herb Sutter

 Guru Meditation Q: What does this code do?

template void append_unique( Container& c, Value v ) { if( find(begin(c), end(c), v) == end(c) ) c.push_back( move(v) ); // anything comparable to end(cont)… assert( !c.empty() ); // what type does .empty return? } // anything testable like a bool… x

 2014 Herb Sutter except material otherwise referenced. 12 C++14 Style 9/13/2014 Herb Sutter

 Counterarguments: “Oi, but it’s unreadable!” “What’s my type?”  This is a weak argument for three reasons:  (Minor) It doesn’t matter to anyone who uses an IDE.  (Major) It reflects bias to code against implementations, not interfaces.  (Major) We already ignore actual types with templates and temporaries. template // what type is Container? Value? void append_unique( Container& c, Value v ) // anything usable like this… { if( find(begin(c), end(c), v) == end(c) ) // what type does find return? c.push_back( move(v) ); // anything comparable to end(cont)… assert( !c.empty() ); // what type does .empty return? } // anything testable like a bool…  We also ignore actual types with virtual functions, function<>, etc.

 With deduction you always get right type. Repetition  P(lying)

 Example: void f( const vector& v ) { vector::iterator i = v.begin(); // ? }

 Options: void f( const vector& v ) { vector::iterator i = v.begin(); // error vector::const_iterator i = v.begin(); // ok + extra thinking auto i = v.begin(); // ok, default }

 2014 Herb Sutter except material otherwise referenced. 13 C++14 Style 9/13/2014 Herb Sutter

 Using deduction makes your code more robust in the face of change.  Deduction tracks the correct type when an expression’s type changes.  Committing to explicit type = silent conversions, needless build breaks.  Examples: int i = f(1,2,3) * 42; // before: ok enough int i = f(1,2,3) * 42.0; // after: silent narrowing conversion auto i = f(1,2,3) * 42.0; // after: still ok, tracks type widget w = factory(); // before: ok enough, returns a widget widget w = factory(); // after: silent conversion, returns a gadget auto w = factory(); // after: still ok, tracks type map::iterator i = begin(dict); // before: ok enough map::iterator i = begin(dict); // after: error, unordered_map auto i = begin(dict); // after: still ok, tracks type

 Deduction guarantees no implicit conversion will happen.  A.k.a. “guarantees better performance by default.”  Committing to an explicit type that requires a conversion means silently getting a conversion whether you expected it or not.

 2014 Herb Sutter except material otherwise referenced. 14 C++14 Style 9/13/2014 Herb Sutter

 Using deduction is your only good (usable and efficient) option for hard-to-spell and unutterable types like:  lambdas,  binders,  detail:: helpers,  template helpers, such as expression templates (when they should stay unevaluated for performance), and  template parameter types, which are anonymized anyway,  … short of resorting to:  repetitive decltype expressions, and  more-expensive indirections like std::function.

 And, yes, “basic deduction” auto x = expr; syntax is almost always less typing.  Mentioned last for completeness because it’s a common reason to like it, but it’s not the biggest reason to use it.

 2014 Herb Sutter except material otherwise referenced. 15 C++14 Style 9/13/2014 Herb Sutter

 Prefer auto x = expr; by default on variable declarations.  It offers so much correctness, clarity, maintainability, performance and simplicity goodness that you’re only hurting yourself (and your code’s future maintainers) if you don’t.  Prefer to habitually program against interfaces, not implementations. We do this all the time in temporaries and templates anyway and nobody bats an eye.  But: Do commit to an explicit type when you really mean it, which nearly always means you want an explicit conversion.  Q: But even then, does “commit to an explicit type” mean “don’t use auto”?

 Deduce to track if you don’t need to commit to a type:  const char* s = “Hello”; auto s = “Hello”;  widget w = get_widget(); auto w = get_widget();  Commit to stick to a specific type. Try it on the right (same syntax order):  employee e{ empid }; auto e = employee{ empid };  widget w{ 12, 34 }; auto w = widget{ 12, 34 };  With heap allocation, type is on the right naturally anyway:  C++98 style: auto w = new widget{};  C++14 style: auto w = make_unique();  Teaser: Does this remind you of anything else in C++11? and C++14?  int f( double ); auto f( double ) -> int; // C++11  auto f( double ) { … } // C++14

 2014 Herb Sutter except material otherwise referenced. 16 C++14 Style 9/13/2014 Herb Sutter

But what about int x = 42; vs. auto x = 42; ?

“OBVIOUSLY int x = 42; is the tersest and clearest style.” Right?

employee e{ empid }; auto e = employee{ empid }; widget w = get_widget(); auto w = get_widget();  Now consider literal suffixes: int x = 42; auto x = 42; float x = 42.; auto x = 42.f; // no narrowing unsigned long x = 42; auto x = 42ul; string x = “42”; auto x = “42”s; // C++14 chrono::nanoseconds x{ 42 }; auto x = 42ns; // C++14  Remember functions, lambdas, and aliases: int f( double ); auto f ( double ) -> int; auto f = [=]( double ) { /*…*/ }; typedef set dict; using dict = set; template struct myvec template { typedef vector type; }; using myvec = vector;

 2014 Herb Sutter except material otherwise referenced. 17 C++14 Style 9/13/2014 Herb Sutter

 The C++ world is moving to left-to-right everywhere:

category name = type and/or initializer ; Auto variables: auto e = employee{ empid }; auto w = get_widget(); Literals: auto x = 42; auto x = 42.f; auto x = 42ul; User-defined literals: auto x = “42”s; auto x = 1.2ns; Function declarations: auto func ( double ) -> int; Named lambdas: auto func = [=]( double ) { /*…*/ }; Aliases (no more typedefs): using dict = set; Template aliases: template using myvec = vector;

 Consider:

auto x = value;

 Q: Does this “=” create a temporary object plus a move/copy?  Standard says “No.” The code T x = a; has exactly the same meaning as T x(a); when a has type T (or derived from T)… and auto x = a; guarantees the types are the same (yay auto) so it always means exactly the same as auto x(a).

 2014 Herb Sutter except material otherwise referenced. 18 C++14 Style 9/13/2014 Herb Sutter

 Consider:

auto x = type{value};

 Q: Does this “=” create a temporary object plus a move/copy?  Standard says “Yes, but”: The compiler may elide the temporary.  In practice, compilers do (and in the future routinely will) elide this temporary+move. However, the type must still be movable (which includes copyable as a fallback).

 Case: (1) Explicit “type{}” + (2) non-(cheaply-)moveable type. auto lock = lock_guard{ }; // error, not movable auto ai = atomic{}; // error, not movable auto a = array{}; // compiles, but needlessly expensive

 Non-cases: Naked init list, proxy type, multi-word name. auto x = { 1 }; // initializer_list auto x = 1; // int auto a = matrix{…}, b = matrix{…}; // some lazily evaluated type auto ab = a * b; // capture proxy (efficient by default) auto c = matrix{ a * b }; // resolve computation auto x = (long long){ 42 }; // use int64_t{42} or 42LL auto y = class X{1,2,3}; // use X{1,2,3};

 2014 Herb Sutter except material otherwise referenced. 19 C++14 Style 9/13/2014 Herb Sutter

 A recent time I resisted using auto, I was wrong.  It came up when changing this legacy code: base* pb = new derived(); to this modern code, where I and others kept not noticing the different types: unique_ptr pb = make_unique(); // too subtle: people keep not seeing it and now I actually do prefer the consistent and nearly-as-terse spelling: auto pb = unique_ptr{ make_unique() }; // explicit and clear: hard to miss it which makes what’s going on nice and explicit – the conversion is more obvious because we’re explicitly asking for it.

1. Deduced and exact, when you want tracking: auto x = init; 2. With explicit type name, when you want to commit: auto x = Type { init };

Note: Guarantees zero implicit conversions/temporaries, zero narrowing conversions, and zero uninitialized variables!

 2014 Herb Sutter except material otherwise referenced. 20 C++14 Style 9/13/2014 Herb Sutter

They’re in headers anyway. (Insert de rigueur modules note here.) C++14 makes it it convenient to not to not repeat yourself. Remember: auto only  exact type, no conversions; explicit return type  stable type, committed.

 2014 Herb Sutter except material otherwise referenced. 21 C++14 Style 9/13/2014 Herb Sutter

Complete “how to pass params” details follow, but the summary fits on a slide… … one slide for “default,” one slide for “optimal”

Observation

“New features get overused.” – B. Stroustrup or “It’s about the lvalues, after all!” – S. Meyers

Just as exception safety isn’t all about writing try and catch, using move semantics isn’t all about writing move and &&

 2014 Herb Sutter except material otherwise referenced. 22 C++14 Style 9/13/2014 Herb Sutter

 The following is the result of recent discussions with many people, including but not limited to the following:  Gabriel Dos Reis  Matthew Fiovarante (&& param  move from)  Howard Hinnant (distinguish copy ctor/op= costs vs. move)  Stephan T. Lavavej (low cost of value return even in C++98)  Scott Meyers (reduce #objects, be aware of costs )  Eric Niebler  Sean Parent  Bjarne Stroustrup (practicality, judgment, design sense)  VC++ MVP discussion list  & many more

Expensive to copy Cheap to copy Moderate cost to copy (e.g., string, BigPOD) (e.g., vector, (e.g., int) or Don’t know (e.g., unfamiliar type, template) BigPOD[])

Out X f() f(X&) *

In/Out f(X&)

In f(X) f(const X&) In & retain copy

“Cheap”  a handful of hot int copies “Moderate cost”  memcpy hot/contiguous ~1KB and no allocation

* or return X* at the cost of a dynamic allocation

 2014 Herb Sutter except material otherwise referenced. 23 C++14 Style 9/13/2014 Herb Sutter

Cheap or Cheap to move (e.g., vector, string) Expensive to move impossible to or Moderate cost to move (e.g., array, BigPOD) (e.g., BigPOD[], copy (e.g., int, or Don’t know (e.g., unfamiliar type, template) array) unique_ptr) Out X f() f(X&) *

In/Out f(X&)

In f(X) f(const X&) In & retain “copy”

Summary of what’s new in C++1x: “Cheap” Defaults  a handful work of hot better int copies “Moderate cost”  memcpy hot/contiguous ~1KB and no allocation

* or return unique_ptr/make_shared_ at the cost of a dynamic allocation

Cheap or Cheap to move (e.g., vector, string) Expensive to move impossible to or Moderate cost to move (e.g., array, BigPOD) (e.g., BigPOD[], copy (e.g., int, or Don’t know (e.g., unfamiliar type, template) array) unique_ptr) Out X f() f(X&) * +1 consistency: In/Out f(X&) same optimization In f(const X&) guidance as overloaded f(X) copy+move construction In & retain copy f(const X&) + f(X&&) & move ** and assignment In & move from f(X&&) **

Summary of what’s new in C++1x: * or return unique_ptr/make_shared_ at the cost of a dynamic allocation  Defaults work better ** special cases can also use+ perfectMore forwardingoptimization (e.g., multipleopportunities in+copy params, conversions)

 2014 Herb Sutter except material otherwise referenced. 24 C++14 Style 9/13/2014 Herb Sutter

Cheap or Cheap to move (e.g., vector, string) Expensive to move impossible to or Moderate cost to move (e.g., array, BigPOD) (e.g., BigPOD[], copy (e.g., int, or Don’t know (e.g., unfamiliar type, template) array) unique_ptr) Out X f() f(X&) * In/Out f(X&)

In f(const X&) f(X) In & retain copy f(const X&) + f(X&&) & move **

In & move from f(X&&) **

Summary of what’s new in C++1x: * or return unique_ptr/make_shared_ at the cost of a dynamic allocation  Defaults work better ** special cases can also use+ perfectMore forwardingoptimization (e.g., multipleopportunities in+copy params, conversions)

When do I write rvalue &&? Only to optimize rvalues Just as exception safety isn’t all about writing try and catch, using move semantics isn’t all about writing move and &&

 2014 Herb Sutter except material otherwise referenced. 25 C++14 Style 9/13/2014 Herb Sutter

Cheap or Cheap to move (e.g., vector, string) Expensive to move impossible to or Moderate cost to move (e.g., array, BigPOD) (e.g., BigPOD[], copy (e.g., int, or Don’t know (e.g., unfamiliar type, template) array) unique_ptr) Out X f() f(X&) In/Out f(X&)

In f(const X&)

In & retain copy f(X) * f(X) & move In & move from ?

* GOOD: this can be faster than C++98 – can move from rvalues; BUT: also can be much slower than C++98 – always incurs a full copy, prevents reusing buffers/state (e.g., for vectors & long strings, incurs memory allocation 100% of the time) BUT: also problematic for noexcept

 Consider: class employee { std::string name_; public: void set_name( /*… ?? …*/ ); // change name_ to new value };  Q: What should we tell people to write here?  Hint: There has been a lot of overthinking going on about this. (I include myself.)

 2014 Herb Sutter except material otherwise referenced. 26 C++14 Style 9/13/2014 Herb Sutter

 Default: const string& class employee { std::string name_; public: void set_name( const std::string& name ) { name_ = name; } };  Always 1 copy assignment – but usually <<50% will alloc  If small (SSO), ~5 int copies, no mem alloc – often dominant  If large, still performs mem alloc <50% of the time

 If optimization justified: Add overload for string&& + move class employee { std::string name_; public: void set_name( const std::string& name ) { name_ = name; } void set_name( std::string&& name ) noexcept { name_ = std::move(name); } };  Optimized to steal from rvalues:  Pass a named object: 1 copy assignment (<<50% alloc), as before  Pass a temporary: 1 move assignment (~5 ints, no alloc  noexcept)  Note: Combinatorial if multiple “in + retain copy” parameters.

 2014 Herb Sutter except material otherwise referenced. 27 C++14 Style 9/13/2014 Herb Sutter

 Another new option in C++11: string + move class employee { std::string name_; public: void set_name( std::string name ) noexcept { name_ = std::move(name); } };  Optimized to steal from rvalues, without overloading:  Pass named object: 1 copy construction (100% alloc if long) + move op=  Pass a temporary: 1 move assignment (~5 ints, no alloc  noexcept-ish)  This “noexcept” is… problematic

 Still another new option in C++11: Templated T&& “perfect forwarding” class employee { std::string name_; public: template, std::string>::value>> void set_name( String&& name ) noexcept(std::is_nothrow_assignable::value) { name_ = std::forward(name); } };  Optimized to steal from rvalues (and more), sort of without overloading:  Pass a named object: 1 copy assignment (<<50% alloc), as before  Pass a temporary: 1 move assignment (~5 ints, no alloc  noexcept)  “Unteachable!” Generates many funcs. Must be in a header. Can’t be virtual.

 2014 Herb Sutter except material otherwise referenced. 28 C++14 Style 9/13/2014 Herb Sutter

VC++ 2013 x64 Release 6000

5000

4000

3000

2000

1000

0 lvalue (1-10) lvalue (1-50) xvalue (1-10) xvalue (1-50) char* (1-10) char* (1-50)

Option 1: const string& Option 2: const string& + string&& Option 3: string Option 4: String&& perfect fwding

Clang/libc++ Release 1200

1000

800

600

400

200

0 lvalue (1-10) lvalue (1-50) xvalue (1-10) xvalue (1-50) char* (1-10) char* (1-50)

Option 1: const string& Option 2: const string& + string&& Option 3: string Option 4: String&& perfect fwding

 2014 Herb Sutter except material otherwise referenced. 29 C++14 Style 9/13/2014 Herb Sutter

G++/libstdc++ x64 Release 1400

1200

1000

800

600

400

200

0 lvalue (1-10) lvalue (1-50) xvalue (1-10) xvalue (1-50) char* (1-10) char* (1-50)

Option 1: const string& Option 2: const string& + string&& Option 3: string Option 4: String&& perfect fwding

G++/libstdc++ vstring x64 Release 1200

1000

800

600

400

200

0 lvalue (1-10) lvalue (1-50) xvalue (1-10) xvalue (1-50) char* (1-10) char* (1-50)

Option 1: const string& Option 2: const string& + string&& Option 3: string Option 4: String&& perfect fwding

 2014 Herb Sutter except material otherwise referenced. 30 C++14 Style 9/13/2014 Herb Sutter

Constructor operator=

Default $$ Move $

Copy $$$$ $$$

 Howard Hinnant: “Don’t blindly assume that the cost of construction is the same as assignment.”  For strings and vectors, “Capacity plays a large role in their performance. Copy construction always allocates (except for short). Copy assignment (except for short) allocates/deallocates 50% of the time with random

capacities on the lhs and rhs. To keep an eye on performance, one must "William of Ockham" by self-created (Moscarlop) - Own work. Licensed under Creative Commons Attribution-Share Alike 3.0 via Wikimedia Commons- count allocations and deallocations.” http://commons.wikimedia.org/wiki/File:William_of_Ockh am.png#mediaviewer/File:William_of_Ockham.png

 William of Occam: ‘Do not multiply entities needlessly.’  Attributed. Talking about hypotheses; applies to ‘entities.’

: “No work is less work than some work.”

 Scott Meyers: ‘It’s a bad habit to just create extra objects.’  “Just create ’em because they’re cheap to move from” is thoughtcrime.

 2014 Herb Sutter except material otherwise referenced. 31 C++14 Style 9/13/2014 Herb Sutter

 This talk focuses on defaults, basic styles and idioms in modern C++.  “Default” != “don’t think.”  “Default” == “don’t overthink.” Esp. don’t optimize prematurely.

 These reinforce (not compete with) the “fundamentals.”  “Write for clarity and correctness first.”  “Avoid premature optimization.” By default, prefer clear over optimal.  “Avoid premature pessimization.” Prefer faster when equally clear.

 Another new option in C++11: string + move class employee { std::string name_; public: void set_name( std::string name ) noexcept { name_ = std::move(name); } };  Optimized to steal from rvalues, without overloading:  Pass named object: 1 copy construction (100% alloc if long) + move op=  Pass a temporary: 1 move assignment (~5 ints, no alloc  noexcept-ish)  This “noexcept” is… problematic

 2014 Herb Sutter except material otherwise referenced. 32 C++14 Style 9/13/2014 Herb Sutter

 There is one place where this is a good idea: Constructors. class employee { std::string name_; std::string addr_; std::string city_; public: void employee( std::string name, std::string addr, std::string city ) : name_{std::move(name)}, addr_{std::move(addr)}, city_{std::move(city)} { } };  Constructors are the primary case of multiple “in + retain copy” params, where overloading const&/&& is combinatorial.  Constructors always construct, so no worries about reusing existing capacity.  Note: Probably prefer not to write the misleading “noexpect”…

 Default: const string& class employee { std::string name_; public: void set_name( const std::string& name ) { name_ = name; } };  Always 1 copy assignment – but usually <<50% will alloc  If small (SSO), ~5 int copies, no mem alloc – often dominant  If large, still performs mem alloc <50% of the time

 2014 Herb Sutter except material otherwise referenced. 33 C++14 Style 9/13/2014 Herb Sutter

 If optimization justified: Add overload for string&& + move class employee { std::string name_; public: void set_name( const std::string& name ) { name_ = name; } void set_name( std::string&& name ) noexcept { name_ = std::move(name); } };  Optimized to steal from rvalues:  Pass a named object: 1 copy assignment (<<50% alloc), as before  Pass a temporary: 1 move assignment (~5 ints, no alloc  noexcept)  Note: Combinatorial if multiple “in + retain copy” parameters.

What is a T&&? A forwarding reference

 2014 Herb Sutter except material otherwise referenced. 34 C++14 Style 9/13/2014 Herb Sutter

void foo( X&& x ); template void bar( Y&& y );  Q: What are the types of the function parameters? What arguments to they accept or reject? What is the parameter for?  A: Fundamentally different.  foo takes rvalue reference to non-const. foo accepts only rvalue X objects. foo’s parameter is to capture temporaries (and other rvalues).  bar takes mumble reference to everything: const, volatile, both, and neither. bar accepts all Y objects. bar’s parameter is for forwarding its argument onward.

 Scott Meyers pointed out that T&& is very different, and needs a name.  He coined “universal reference.”  For his book whose final galleys are due, um, today.  Here at CppCon, a few of us met and ultimately agreed that this does need a name. (Thanks, Scott.)  But we still disliked “universal.” (Sorry, Scott.)  We think the right name is “forwarding reference.”  The committee/community may disagree. Time will tell.  In the meantime, Scott will add a footnote and index entry for “forwarding reference,” and switch to it in future printings if the community agrees. (Thanks, Scott!)

 2014 Herb Sutter except material otherwise referenced. 35 C++14 Style 9/13/2014 Herb Sutter

 Use && only for parameter/return types:  myclass&& rvalue references to optimize rvalues, usually overloading const& / && – note this covers the move SMFs! void f( const string& ); // default way to express “in + retain a copy” void f( string&& ); // what to add to additionally optimize for rvalues  T&& forwarding references to write forwarders, which are neutral code between unknown callers and callees and want to preserve rvalueness/cv-ness.  Note this includes the new proposed for(e:c), which is… drum roll… a neutral forwarder between a collection/range and the calling code.  Also includes generic lambda auto&& parameters… use for forwarders only.  Don’t use auto&& for local variables.  You should know whether your variable is const/volatile or not!  (Except rarely if you’re just handing it off… in the body of a forwarder.)

Yes, C++11 has multiple return values! (Who knew?)

 2014 Herb Sutter except material otherwise referenced. 36 C++14 Style 9/13/2014 Herb Sutter

 Given a set myset, consider: // C++98 pair::iterator,bool> result = myset.insert( “Hello” ); if (result.second) do_something_with( result.first ); // workaround

// C++11 – sweet backward compat auto result = myset.insert( “Hello” ); // nicer syntax, and the if (result.second) do_something_with( result.first ); // workaround still works

// C++11 – sweet forward compat, can treat as multiple return values tie( iter, success ) = myset.insert( “Hello” ); // normal return value if (success) do_something_with( iter );

C++ developers (~3M)

libstdc++ developers (~30) + libc++ developers (~5-7) + Boost developers (~300?) + ISO WG21 attenders (~300?)

 2014 Herb Sutter except material otherwise referenced. 37 C++14 Style 9/13/2014 Herb Sutter

Questions?

 2014 Herb Sutter except material otherwise referenced. 38