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.
Don’t use Owning
Do use Non-Owning
When deferencing a global (static or heap) or aliased local refcounted pointers e.g.
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.
Use
Prefer declaring local variables using
Deduced and exact, when you want tracking:
Q: Does this “=” create a temporary objects plus a move/copy?
A: Standard says “No”. The code
Write explicit typename, when you want to commit:
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
There are cases where you can’t use “
Just as exception safety isn’t all about writing
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.
Use
(2)
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
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 usingunique_ptrwherever possible, including when you don’t know whether the object will actually ever be shared. That is, write
make_unqiueby default or
make_sharedwhen needed.
Don’t use Owning
*,
newor
deleteany 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_potherwise
g_pmight 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
autosince C++14, Named lambdas, Aliases with
using(no more
typedef), Template aliases. As to auto variables, here is another example where
autois 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 “
autostyle”:
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
tryand
catch, using move semantics isn’t all about writing
moveand
&&.
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
相关文章推荐
- 在VS2010下,用C语言编写pthread多线程程序的配置
- 利用typedef定义函数指针
- c++类模板和函数模板
- xcode 中编译C++, 提示 iostream no this file
- C语言的实参与形参
- 判断两矩形是否相交,相交的话 求出相交的面积和相交处比例
- C++深入 细节
- C++ 构造函数 析构函数 拷贝构造函数 运算符重载解析。
- c++ 类作用域中的名字查找
- 指针函数与函数指针的区别
- 【Best Time to Buy and Sell Stock II】cpp
- C++中 引用&与取地址&的区别
- 【Best Time to Buy and Sell Stock】cpp
- 标准c++库和stl库,boost库,qt库的总结(一)
- 《C++编程思想》 第一章 对象的演化
- C++对象模型之默认构造函数的构造操作
- c++运算符重载
- c++语言实现装饰模式代码示例
- c++位移计算
- switch case语句块default的认识