您的位置:首页 > 编程语言 > C语言/C++

Back to the Basics! Essentials of Modern C++ Style

2015-05-30 11:37 567 查看
Herb Sutter @ CppCon2014, video can be found here.

Default == don’t overthink. Esp. don’t optimize prematurely.

Write for clarity and correctness first.

Avoid premature optimization. By default, prefer clear over optimal.

Avoid premature pessimization. Prefer faster when equally clear.

Raw Pointers vs Smart Pointers

Express ownership using
unique_ptr
wherever possible, including when you don’t know whether the object will actually ever be shared. That is, write
make_unqiue
by default or
make_shared
when needed.

Don’t use Owning
*
,
new
or
delete
any more, except rarely inside the implementation details of low-level data structures.

Do use Non-Owning
*
and
&
, especially for parameters. Prefer passing objects by
*
or by
&
as usual, just like always.

When deferencing a global (static or heap) or aliased local refcounted pointers e.g.
shared_ptr<widget> g_p
, take its unaliased + local copy at the top of a call tree
auto pin = g_p
otherwise
g_p
might disappear.



Don’t copy/assign refcounted smarted pointers, including pass-by-value or in loops, unless you really want the semantics they express: altering object lifetime. In that case, refer to the following code.

unique_ptr<widget> factory(); // source - produces widget
void sink(unique_ptr<widget>); // sink - consumes widget
void reseat(unique_ptr<widget>&); // "will" or "might" reseat ptr
void thinke(const unique_ptr<widget>&); // usually not what you want

shared_ptr<widget> factory();// source + shared ownership
void share(shared_ptr<widget>); // share - "will" retain refcount
void reseat(shared_ptr<widget>&); // "will" or "might" reseat ptr
void may_share(const shared_ptr<widget>&); // "might" retain refcount


Use
auto
whenever possible

Prefer declaring local variables using
auto
, whether the type should be track or stick. This guarantees zero implicit coversions/temporaries, zero narrowing conversions and zero uninitialized variables.

Deduced and exact, when you want tracking:
auto x = init;


Q: Does this “=” create a temporary objects plus a move/copy?

A: 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, so it always means exactly the same as auto
x(a)
.

Write explicit typename, when you want to commit:
auto x = Type{init};


Q: Does this “=” create a temporary objects plus a move/copy?

A: Standard says “Yes, but”: the compiler 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).

The C++ world is moving to left-to-right: Auto variables, standard-defined literals, User-defined literals, Function declarations (tailing return type or just
auto
since C++14, Named lambdas, Aliases with
using
(no more
typedef
), Template aliases. As to auto variables, here is another example where
auto
is better:

base* pb = new derived();
unique_ptr<base> pb = make_unique<derived>(); // too subtle: people keep not seeing it
auto pb = unique_ptr<base>{make_unique<derived>()}; // explicit and clear: hard to miss it


There are cases where you can’t use “
auto
style”:
type{}
with non-(cheaply-)movable type.

auto lock = lock_guard<mutex>{m}; // error, not movable
auto ai = atomic<int>{}; // error, not movable
auto a = array<int, 50>{}; // compiles, but needlessly expensive


Return-by-value vs Pass-by-value

Use return-by-value way more often, but don’t overuse pass-by-value.

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







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 count allocations and deallocations.

Constructors are the primary case of multiple “in + retain copy” (pass-by-value) parameters, where overloading const&/&& is combinatorial.

Uses and Abuses of Forwarding Reference

The name of
&&
is expected to be changed from universal reference to forwarding reference in the new print of Scott Meyer’s “Effective Modern C++”.

Use
&&
only for parameter/return types. (1)
myclass&&
rvalue references to optimize rvalues, usually overloading
const& /&&
.

(2)
T&&
forwarding references to write forwarders, which are neutral code between unknown callers and callees and want to preserve rvalueness/cv-ness.

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: