《Effective Modern C++》要点中英文对照
自己翻译着玩的,尽量简单易记,书还是要看的,这个做为一个提纲没事看看。
- CHAPTER 1 Deducing Types
- 章节1 类型推导
- CHAPTER 2 auto
- 章节2 auto
- CHAPTER 3 Moving to Modern C++
- 章节3 迁移到现代C++
- Item 7:Distinguish between () and {} when creating objects.
- 条款7:创建对象时区分()和{}。
- Item 8: Prefer nullptr to 0 and NULL.
- 条款8:优先使用nullptr,而不是0和NULL。
- Item 9:Prefer alias declarations to typedef s.
- 条款9:优先使用alias声明,而不是typedef。
- Item 10:Prefer scoped enum s to unscoped enum s.
- 条款10:优先使用范围枚举,而不是非范围枚举。
- Item 11:Prefer deleted functions to private undefined ones.
- 条款11:优先使用deleted函数,而不是私有未定义函数。
- Item 12:Declare overriding functions override
- 条款12:把重写函数声明为override
- Item 13:Prefer const_iterator s to iterator s.
- 条款13:优先使用const_iterator, 而不是其它的iterator。
- Item 14:Declare functions noexcept if they won’t emit exceptions.
- 条款14:如果函数不抛出异常则声明为noexcept
- Item 15:Use constexpr whenever possible.
- 条款15:只要有可能就使用constexpr。
- Item 16:Make const member functions thread safe.
- 条款16:使const成员成为线程安全的。
- Item 17:Understand special member function generation.
- 条款17:理解特殊成员函数的生成。
- CHAPTER 4 Smart Pointers
- 章节4 智能指针
- Item 18:Use std::unique_ptr for exclusive-ownership resource management.
- 条款18:使用std::unique_ptr管理独占资源。
- Item 19:Use std::shared_ptr for shared-ownership resource management.
- 条款19: 使用std::shared_ptr管理共享资源。
- Item 20:Use std::weak_ptr for std::shared_ptr - like pointers that can dangle.
- 条款20:使用std::weak_ptr代替可能会发生悬空指针的std::shared_ptr。
- Item 21:Prefer std::make_unique and std::make_shared to direct use of new
- 条款21:优先使用std::make_unique和std::make_shared,而不是直接使用new。
- Item 22:When using the Pimpl Idiom, define special member functions in the implementation file.
- 条款22:如果使用Pimpl惯用法,则要在实现文件中定义特殊成员函数。
- CHAPTER 5 Rvalue References, Move Semantics, and Perfect Forwarding
- 章节5 右值引用,移动语义和完美转发
- Item 23:Understand std::move and std::forward.
- 条款23: 理解std::move和std::forward。
- Item 24:Distinguish universal references from rvalue references.
- 条款24:区分通用引用和右值信引用。
- Item 25:Use std::move on rvalue references, std::forward on universal references.
- 条款25:对右值引用使用std::move, 对通用引用使用std::forward。
- Item 26:Avoid overloading on universal references.
- 条款26:避免对通用引用进行重载。
- Item 27:Familiarize yourself with alternatives to overloading on universal references.
- 条款27:熟悉重载通用引用函数的其它替代方法
- Item 28:Understand reference collapsing.
- 条款28:理解引用折叠。
- Item 29:Assume that move operations are not present, not cheap, and not used.
- 条款29: 要假定移动操作是不存在在,不是廉价的,也不是可用的。
- Item 30:Familiarize yourself with perfect forwarding failure cases.
- 条款20:熟悉完美转发失败案例。
- CHAPTER 6 Lambda Expressions
- 章节6 Lambda表达式
- CHAPTER 7 The Concurrency API
- 章节7 并发API
- Item 35:Prefer task-based programming to thread-based.
- 条款35:优先采用基于task的编程方法,而不是基于thread(相关的类)。
- Item 36:Specify std::launch::async if asynchronicity is essential.
- 条款36:如果需要异步处理,请指定std::launch::async。
- Item 37:Make std::threads unjoinable on all paths.
- 条款37:使std::threads在任何路径下都是不能join的。
- Item 38:Be aware of varying thread handle destructor behavior.
- 条款38:要小心不同的线程句柄析构行为。
- Item 39:Consider void futures for one-shot event communication.
- 条款39: 考虑对于一次性事件通信中使用void future。
- Item 40:Use std::atomic for concurrency, volatile for special memory.
- 条款40:使用std::atomic处理并发,使用volatile处理特殊内存。
- CHAPTER 8 Tweaks
- 章节8 小改进
CHAPTER 1 Deducing Types
章节1 类型推导
Item 1:Understand template type deduction.
条款1:理解模板类型推导.
Things to Remember
需要记住:
- During template type deduction, arguments that are references are treated as non-references, i.e., their reference-ness is ignored.
- 推导模版类型时,引用的值视为非引用,即忽略引用。
- When deducing types for universal reference parameters, lvalue arguments get special treatment.
- 推导通用引用类型参数时,左值特殊处理。
- When deducing types for by-value parameters, const and/or volatile arguments are treated as non-const and non-volatile.
- 推导传值参数时,忽略const和volatile。
- During template type deduction, arguments that are array or function names decay to pointers, unless they’re used to initialize references.
- 推导模版类型时,参数是数组或函数名则退化为指针,除非用来初始化引用。
Item 2:Understand auto type deduction.
条款2:理解auto类型推导.
Things to Remember
需要记住:
- auto type deduction is usually the same as template type deduction, but auto type deduction assumes that a braced initializer represents a std::initializer_list, and template type deduction doesn’t.
- 推导auto类型一般和推导模版类型是一致的,但auto类型推导对于大括号初始化{}会推导为std::initializer_list,模版类型推导则不会。
- auto in a function return type or a lambda parameter implies template type deduction, not auto type deduction.
- 做为函数返回类型或lambda参数中的auto类型推导意味着模版类型推导,而不做为auto类型推导。
Item 3:Understand decltype.
条款3:理解decltype.
Things to Remember
需要记住:
- decltype almost always yields the type of a variable or expression without any modifications.
- decltype几乎总是推导出变量或表达式的类型,不做任何修改。
- For lvalue expressions of type T other than names, decltype always reports a type of T&.
- 类型为T的左值表达式而不是名称,decltype总是推导成引用T&。
- C++14 supports decltype(auto), which, like auto, deduces a type from its initializer, but it performs the type deduction using the decltype rules.
- C++14支持decltype(auto),和auto一样,通过初始值推导,但使用decltype规则。
Item 4:Know how to view deduced types.
条款4:知道如何查看推导出来的类型.
Things to Remember
需要记住:
- Deduced types can often be seen using IDE editors, compiler error messages, and the Boost TypeIndex library.
- 推导出来的类型通常可以使用IDE编辑器,编译错误信息或Boost TypeIndex库查看到。
- The results of some tools may be neither helpful nor accurate, so an understanding of C++’s type deduction rules remains essential.
- 有些工具查看到的结果可能没有任何帮助或者就是错误的,所以理解类型推导规则还是有用的。
CHAPTER 2 auto
章节2 auto
Item 5:Prefer auto to explicit type declarations.
条款5: 优先使用auto,而不是显式的类型声明
Things to Remember
需要记住:
- auto variables must be initialized, are generally immune to type mismatches that can lead to portability or efficiency problems, can ease the process of refactoring, and typically require less typing than variables with explicitly specified types.
- auto变量必须初始化,基本上不会有类型不匹配导致的可移值问题或效率问题的影响,也可以简化重构过程,一般也比显式指定类型需要更少的键盘输入。
- auto-typed variables are subject to the pitfalls described in Items 2 and 6.
- auto类型的变量请查看条款2和条款6中描述的陷阱。
Item 6:Use the explicitly typed initializer idiom when auto deduces undesired types.
条款6:当auto推导出的类型不是想要的类型时,使用显示类型初始化的惯用语法。
Things to Remember
需要记住:
- “Invisible” proxy types can cause auto to deduce the “wrong” type for an initializing expression.
- “不可见的”代理类型会导致auto对初始化表达式推导出“错误的”类型。
- The explicitly typed initializer idiom forces auto to deduce the type you want it to have.
- 显示类型初始化的惯用语法迫使auto推导出想要的类型。
CHAPTER 3 Moving to Modern C++
章节3 迁移到现代C++
Item 7:Distinguish between () and {} when creating objects.
条款7:创建对象时区分()和{}。
Things to Remember
需要记住:
- Braced initialization is the most widely usable initialization syntax, it prevents narrowing conversions, and it’s immune to C++’s most vexing parse.
- 花括号初始化方法是最为广泛使用的初始化语法,可以防止类型转换变窄,也不受C++烦人的解析问题影响。
- During constructor overload resolution, braced initializers are matched to std::initializer_list parameters if at all possible, even if other constructors offer seemingly better matches.
- 构造函数的重载解析中,花括号初始化方法只要可能就会匹配std::initializer_list参数,即使有其它的构造函数提供了看上去更好的匹配参数。
- An example of where the choice between parentheses and braces can make a significant difference is creating a std::vector
with two arguments. - std::vector<数字类型>在使用圆括号和花括号初始化时意义完全不同。
- Choosing between parentheses and braces for object creation inside templates can be challenging.
- 在模板中的对象创建时选择圆括号还是花括号是一个挑战。
Item 8: Prefer nullptr to 0 and NULL.
条款8:优先使用nullptr,而不是0和NULL。
Things to Remember
需要记住:
- Prefer nullptr to 0 and NULL.
- 优先使用nullptr,而不是0和NULL。
- Avoid overloading on integral and pointer types.
- 避免整形或指针类型的重载。
Item 9:Prefer alias declarations to typedef s.
条款9:优先使用alias声明,而不是typedef。
Things to Remember
需要记住:
- typedefs don’t support templatization, but alias declarations do.
- typedefs不支持模板化,alias声明支持。
- Alias templates avoid the “::type” suffix and, in templates, the “typename” prefix often required to refer to typedefs.
- alias模板避免了“::type”后缀,以及在模板中的用于typedefs的“typename”前缀。
- C++14 offers alias templates for all the C++11 type traits transformations.
- 所有C++11中类型traits转换,C++14都提供了alias模板。
Item 10:Prefer scoped enum s to unscoped enum s.
条款10:优先使用范围枚举,而不是非范围枚举。
Things to Remember
需要记住:
- C++98-style enums are now known as unscoped enums.
- C++98类型的枚举就是非范围枚举。
- Enumerators of scoped enums are visible only within the enum. They convert to other types only with a cast.
- 范围枚举的枚举器只在枚举内部可见,只能通过cast转换为其它类型。
- Both scoped and unscoped enums support specification of the underlying type. The default underlying type for scoped enums is int. Unscoped enums have no default underlying type.
- 范围枚举和非范围枚举都支持指定底层类型。范围枚举的默认底层类型是int, 而非范围没有默认底层类型。
- Scoped enums may always be forward-declared. Unscoped enums may be forward-declared only if their declaration specifies an underlying type.
- 范围枚举总是可以前向声明,而非范围枚举只有指定底层类型时才可以前向声明。
Item 11:Prefer deleted functions to private undefined ones.
条款11:优先使用deleted函数,而不是私有未定义函数。
Things to Remember
需要记住:
- Prefer deleted functions to private undefined ones.
- 优先使用deleted函数,而不是私有未定义函数。
- Any function may be deleted, including non-member functions and template instantiations.
- 任何函数都可以deleted, 包括非成员函数和模板实例函数。
Item 12:Declare overriding functions override
条款12:把重写函数声明为override
Things to Remember
需要记住:
- Declare overriding functions override.
- 把重写函数声明为override
- Member function reference qualifiers make it possible to treat lvalue and rvalue objects (*this) differently.
- 成员函数引用限定符可以区别对待左值和右值对象。
Item 13:Prefer const_iterator s to iterator s.
条款13:优先使用const_iterator, 而不是其它的iterator。
Things to Remember
需要记住:
- Prefer const_iterators to iterators.
- 优先使用const_iterator, 而不是其它的iterator。
- In maximally generic code, prefer non-member versions of begin, end, rbegin, etc., over their member function counterparts.
- 大多数泛型代码中,优先使用非成员函数版本的begin, end, rbegin等等,而不是相应的成员函数。
Item 14:Declare functions noexcept if they won’t emit exceptions.
条款14:如果函数不抛出异常则声明为noexcept
Things to Remember
需要记住:
- noexcept is part of a function’s interface, and that means that callers may depend on it.
- noexcept是函数接口的一部分,意味着调用者必须依赖它。
- noexcept functions are more optimizable than non-noexcept functions.
- noexcept函数更容易优化。
- noexcept is particularly valuable for the move operations, swap, memory deallocation functions, and destructors.
- noexcept在移动操作,交换,内存释放函数,析构函数中特别有价值。
- Most functions are exception-neutral rather than noexcept.
- 大多数函数是异常中立的,而不是noexcept。
Item 15:Use constexpr whenever possible.
条款15:只要有可能就使用constexpr。
Things to Remember
需要记住:
- constexpr objects are const and are initialized with values known during compilation.
- constexpr对象是常量并且是在编译期初始化的。
- constexpr functions can produce compile-time results when called with arguments whose values are known during compilation.
- constexpr函数在给定的参数是编译期已知的情况下可以生成编译期结果。
- constexpr objects and functions may be used in a wider range of contexts than non-constexpr objects and functions.
- constexpr对象和函数比起非constexpr对象和函数,可以使用在更宽泛的上下文范围。
- constexpr is part of an object’s or function’s interface.
- constexpr是对象接口或函数接口的一部分。
Item 16:Make const member functions thread safe.
条款16:使const成员成为线程安全的。
Things to Remember
需要记住:
- Make const member functions thread safe unless you’re certain they’ll never be used in a concurrent context.
- 除非确定不会在并发环境中使用,否则const成员一定要是线程安全的。
- Use of std::atomic variables may offer better performance than a mutex, but they’re suited for manipulation of only a single variable or memory location.
- std::atomic变量比mutex性能更好,但只能用于操作单一变量或单一内存位置。
Item 17:Understand special member function generation.
条款17:理解特殊成员函数的生成。
Things to Remember
需要记住:
- The special member functions are those compilers may generate on their own: default constructor, destructor, copy operations, and move operations.
- 特殊成员函数就是编译器自动生成的:默认构造函数,析构函数,拷贝操作,移动操作。
- Move operations are generated only for classes lacking explicitly declared move operations, copy operations, and a destructor.
- 移动操作函数只有在没有显式声明移动操作,拷贝操作,析构函数时才会生成。
- The copy constructor is generated only for classes lacking an explicitly declared copy constructor, and it’s deleted if a move operation is declared. The copy assignment operator is generated only for classes lacking an explicitly declared copy assignment operator, and it’s deleted if a move operation is declared. Generation of the copy operations in classes with an explicitly declared destructor is deprecated.
- 拷贝构造函数只有在没有显式声明拷贝构造函数时才会生成,而且如果声明了移动操作就会被删除。拷贝赋值操作只有在没有显式声明拷贝赋值操作符才会生成,而且声明了移动操作就会删除。如果显式声明了析构函数,则拷贝操作就会过时。
- Member function templates never suppress generation of special member functions.
- 成员函数模板永远不会阻止特殊成员函数的生成。
CHAPTER 4 Smart Pointers
章节4 智能指针
Item 18:Use std::unique_ptr for exclusive-ownership resource management.
条款18:使用std::unique_ptr管理独占资源。
Things to Remember
需要记住:
- std::unique_ptr is a small, fast, move-only smart pointer for managing resources with exclusive-ownership semantics.
- std::unique_ptr小巧,快速,只能移动,用于管理独占资源。
- By default, resource destruction takes place via delete, but custom deleters can be specified. Stateful deleters and function pointers as deleters increase the size of std::unique_ptr objects.
- 默认情况下资源析构使用delete, 但可以指定自定义的删除器。有状态的删除器或函数指针会增加std::unique_ptr对象的大小。
- Converting a std::unique_ptr to a std::shared_ptr is easy.
- std::unique_ptr很容易转换为std::shared_ptr。
Item 19:Use std::shared_ptr for shared-ownership resource management.
条款19: 使用std::shared_ptr管理共享资源。
Things to Remember
需要记住:
- std::shared_ptrs offer convenience approaching that of garbage collection for the shared lifetime management of arbitrary resources.
- std::shared_ptrs对于随意的资源的共享生命周期管理提供方便的垃圾回收处理方法。
- Compared to std::unique_ptr, std::shared_ptr objects are typically twice as big, incur overhead for control blocks, and require atomic reference count manipulations.
- 相对于std::unique_ptr来说,std::shared_ptr对象通常大一倍,主要是控制块,原子引用计数操作导致。
- Default resource destruction is via delete, but custom deleters are supported. The type of the deleter has no effect on the type of the std::shared_ptr.
- 默认资源的析构是通过delete, 但也支持自定义删除器。删除器的类型对std::shared_ptr的类型不起作用。
- Avoid creating std::shared_ptrs from variables of raw pointer type.
- 避免从原始指针类型的变量生成std::shared_ptrs。
Item 20:Use std::weak_ptr for std::shared_ptr - like pointers that can dangle.
条款20:使用std::weak_ptr代替可能会发生悬空指针的std::shared_ptr。
Things to Remember
需要记住:
- Use std::weak_ptr for std::shared_ptr-like pointers that can dangle.
- 使用std::weak_ptr代替可能会发生悬空指针的std::shared_ptr。
- Potential use cases for std::weak_ptr include caching, observer lists, and the prevention of std::shared_ptr cycles.
- 潜在的使用std::weak_ptr的情景有缓存,观察者列表,避免std::shared_ptr循环引用。
Item 21:Prefer std::make_unique and std::make_shared to direct use of new
条款21:优先使用std::make_unique和std::make_shared,而不是直接使用new。
Things to Remember
需要记住:
- Compared to direct use of new, make functions eliminate source code duplication, improve exception safety, and, for std::make_shared and std::allocate_shared, generate code that’s smaller and faster.
- 相对于直接使用new来说,make函数消除了源代码重复,提升了异常安全,而且std::make_shared和std::allocate_shared都会生成更小更快的代码。
- Situations where use of make functions is inappropriate include the need to specify custom deleters and a desire to pass braced initializers.
- 不适合使用make函数的情况有指定自定义的删除器,需要传递括号初始化器。
- For std::shared_ptrs, additional situations where make functions may be ill-advised include (1) classes with custom memory management and (2) systems with memory concerns, very large objects, and std::weak_ptrs that outlive the corresponding std::shared_ptrs.
- 对std::shared_ptrs来说,make函数不推荐使用的其它情况还有(1)有自定义内存管理的类(2)有内存问题的系统,非常大的对象,以及std::weak_ptrs比std::shared_ptrs的生命还要长的情况。
Item 22:When using the Pimpl Idiom, define special member functions in the implementation file.
条款22:如果使用Pimpl惯用法,则要在实现文件中定义特殊成员函数。
Things to Remember
需要记住:
- The Pimpl Idiom decreases build times by reducing compilation dependencies between class clients and class implementations.
- Pimpl惯用法通过减少类的实现和类的客户的编译依赖关系缩减了编译时间。
- For std::unique_ptr pImpl pointers, declare special member functions in the class header, but implement them in the implementation file. Do this even if the default function implementations are acceptable.
- 如果std::unique_ptr用于pImpl指针,则在类的头文件中声明特殊成员函数,在实现文件中实现。即使默认的函数实现可以接受的话也要这么做。
- The above advice applies to std::unique_ptr, but not to std::shared_ptr.
- 以上建议适用于std::unique_ptr,但不适用于std::shared_ptr。
CHAPTER 5 Rvalue References, Move Semantics, and Perfect Forwarding
章节5 右值引用,移动语义和完美转发
Item 23:Understand std::move and std::forward.
条款23: 理解std::move和std::forward。
Things to Remember
需要记住:
- std::move performs an unconditional cast to an rvalue. In and of itself, it doesn’t move anything.
- std::move无条件转换为右值,就其本身而言,它不移动任何东西。
- std::forward casts its argument to an rvalue only if that argument is bound to an rvalue.
- std::forward只有在绑定的参数是右值时才会将参数转换为右值。
- Neither std::move nor std::forward do anything at runtime.
- std::move和std::forward在运行时不做任何事情。
Item 24:Distinguish universal references from rvalue references.
条款24:区分通用引用和右值信引用。
Things to Remember
需要记住:
- If a function template parameter has type T&& for a deduced type T, or if an object is declared using auto&&, the parameter or object is a universal reference.
- 如果函数模板参数有类型T&&并且需要推导T,或者对象声明为auto&&, 则参数或对象是通用引用。
- If the form of the type declaration isn’t precisely type&&, or if type deduction does not occur, type&& denotes an rvalue reference.
- 如果类型声明的格式不是精确的type&&, 或不需要类型推导,type&&就是右值引用。
- Universal references correspond to rvalue references if they’re initialized with rvalues. They correspond to lvalue references if they’re initialized with lvalues.
- 通用引用如果使用右值初始化的话,则和右值引用是一致的。如果是用左值初始化的话,则与左值引用是一致的。
Item 25:Use std::move on rvalue references, std::forward on universal references.
条款25:对右值引用使用std::move, 对通用引用使用std::forward。
Things to Remember
需要记住:
- Apply std::move to rvalue references and std::forward to universal references the last time each is used.
- 最后一次使用时,对右值引用使用std::move, 对通用引用使用std::forward。
- Do the same thing for rvalue references and universal references being returned from functions that return by value.
- 返回值是传值时,同上面一样。
- Never apply std::move or std::forward to local objects if they would otherwise be eligible for the return value optimization.
- 如果本地对象有可能做返回值优化的话,永远也不要对本地对象使用std::move或std::forward。
Item 26:Avoid overloading on universal references.
条款26:避免对通用引用进行重载。
Things to Remember
需要记住:
- Overloading on universal references almost always leads to the universal reference overload being called more frequently than expected.
- 重载通用引用几乎总是超预期地频繁调用了通用引用的重载。
- Perfect-forwarding constructors are especially problematic, because they’re typically better matches than copy constructors for non-const lvalues, and they can hijack derived class calls to base class copy and move constructors.
- 完美转发构造函数特别有问题,因为比non-const左值的拷贝构造函数有更好的匹配,这样就会派生类调用基类的拷贝构造函数和移动构造函数。
Item 27:Familiarize yourself with alternatives to overloading on universal references.
条款27:熟悉重载通用引用函数的其它替代方法
Things to Remember
需要记住:
- Alternatives to the combination of universal references and overloading include the use of distinct function names, passing parameters by lvalue-reference-to-const, passing parameters by value, and using tag dispatch.
- 通用引用和重载的组合的替代方法有使用不同的函数名,通过常量的左值引用传递参数,通过值传递参数,以及使用标记调度。
- Constraining templates via std::enable_if permits the use of universal references and overloading together, but it controls the conditions under which compilers may use the universal reference overloads.
- 通过std::enable_if约束模板可以允许通用引用和重载一起使用,但会控制编译器使用通用引用重载的条件。
- Universal reference parameters often have efficiency advantages, but they typically have usability disadvantages.
- 通用引用参数经常会有提升效率的优点,但是通常也会有使用上的缺点。
Item 28:Understand reference collapsing.
条款28:理解引用折叠。
Things to Remember
需要记住:
- Reference collapsing occurs in four contexts: template instantiation, auto type generation, creation and use of typedefs and alias declarations, and decltype.
- 引用折叠发生在四种情况:模板实例化,自动类型生成,typedef和alias声明的创建和使用,decltype。
- When compilers generate a reference to a reference in a reference collapsing context, the result becomes a single reference. If either of the original references is an lvalue reference, the result is an lvalue reference. Otherwise it’s an rvalue reference.
- 当编译器在引用折叠环境中生成引用的引用时,结果就会成为单引用。如果原始的引用有一个是左值引用,则结果就是左值引用,否则就是右值引用。
- Universal references are rvalue references in contexts where type deduction distinguishes lvalues from rvalues and where reference collapsing occurs.
- 通用引用是右值引用的情况有,类型推导可以区分左值和右值时,以及发生引用折叠时。
Item 29:Assume that move operations are not present, not cheap, and not used.
条款29: 要假定移动操作是不存在在,不是廉价的,也不是可用的。
Things to Remember
需要记住:
- Assume that move operations are not present, not cheap, and not used.
- 要假定移动操作是不存在在,不是廉价的,也不是可用的。
- In code with known types or support for move semantics, there is no need for assumptions.
- 已知类型或支持移动语义类型的代码中,不需要有假定。
Item 30:Familiarize yourself with perfect forwarding failure cases.
条款20:熟悉完美转发失败案例。
Things to Remember
需要记住:
- Perfect forwarding fails when template type deduction fails or when it deduces the wrong type.
- 如果模板类型推导失败或推导出错误的类型时,完美转发就会失败。
- The kinds of arguments that lead to perfect forwarding failure are braced initializers, null pointers expressed as 0 or NULL, declaration-only integral const static data members, template and overloaded function names, and bitfields.
- 导致完美转发失败的参数类型有括号初始化器,使用0或NULL的指针,整形常量静态数据成员的声明,模板和重载函数名称,位成员。
CHAPTER 6 Lambda Expressions
章节6 Lambda表达式
Item 31:Avoid default capture modes.
条款31:避免默认的捕捉模式。
Things to Remember
需要记住:
- Default by-reference capture can lead to dangling references.
- 默认的传引用操作捕捉会导致悬空引用。
- Default by-value capture is susceptible to dangling pointers (especially this), and it misleadingly suggests that lambdas are self-contained.
- 默认的传值操作捕捉容易受悬空指针影响(特别是这里),并且会误导成lambdas是自包含的。
Item 32:Use init capture to move objects into closures.
条款32:使用init捕捉来移动对象到闭包。
Things to Remember
需要记住:
- Use C++14’s init capture to move objects into closures.
- 使用c++14的init捕捉来移动对象到闭包。
- In C++11, emulate init capture via hand-written classes or std::bind.
- C++11中,通过手写的类或std::bind来模仿init捕捉。
Item 33:Use decltype on auto&& parameters to std::forward them.
条款33:使用decltype调用std::forward移动auto&&参数。
Things to Remember
需要记住:
- Use decltype on auto&& parameters to std::forward them.
- 使用decltype调用std::forward移动auto&&参数。
Item 34:Prefer lambdas to std::bind
条款34:优先使用lambdas,而不是std::bind
Things to Remember
需要记住:
- Lambdas are more readable, more expressive, and may be more efficient than using std::bind.
- Lambdas更容易阅读,更快捷,并且比std::bind更高效。
- In C++11 only, std::bind may be useful for implementing move capture or for binding objects with templatized function call operators.
- 只有在C++11中,std::bind在实现移动捕捉或绑定对象到模板化的函数调用操作符上可能会有用。
CHAPTER 7 The Concurrency API
章节7 并发API
Item 35:Prefer task-based programming to thread-based.
条款35:优先采用基于task的编程方法,而不是基于thread(相关的类)。
Things to Remember
需要记住:
- The std::thread API offers no direct way to get return values from asynchronously run functions, and if those functions throw, the program is terminated.
- std::thread API从异步运行函数中得到非直接的结果,如果函数抛出异常,则程序终止。
- Thread-based programming calls for manual management of thread exhaustion, oversubscription, load balancing, and adaptation to new platforms.
- 基于Thread的编程方法调用需要手工管理线程耗尽、过度订阅、负载均衡,以及适应新平台等问题。
- Task-based programming via std::async with the default launch policy handles most of these issues for you.
- 基于Task的编程方法通过std::async使用默认加载策略来处理大多数的问题。
Item 36:Specify std::launch::async if asynchronicity is essential.
条款36:如果需要异步处理,请指定std::launch::async。
Things to Remember
需要记住:
- The default launch policy for std::async permits both asynchronous and synchronous task execution.
- std::async的默认加载策略既允许异步执行,也允许同步的执行。
- This flexibility leads to uncertainty when accessing thread_locals, implies that the task may never execute, and affects program logic for timeout-based wait calls.
- 灵活性也会导致访问thread_local时产生不确定性,线程也许永远不会执行,也会影响基于超时等待调用的程序逻辑。
- Specify std::launch::async if asynchronous task execution is essential.
- 如果需要异步处理,请指定std::launch::async。
Item 37:Make std::threads unjoinable on all paths.
条款37:使std::threads在任何路径下都是不能join的。
Things to Remember
需要记住:
- Make std::threads unjoinable on all paths.
- 使std::threads在任何路径下都是不能join的。
- join-on-destruction can lead to difficult-to-debug performance anomalies.
- 在析构函数上join会导致难以调试的性能问题。
- detach-on-destruction can lead to difficult-to-debug undefined behavior.
- 在析构函数上detach会导致难以调试的未定义行为。
- Declare std::thread objects last in lists of data members.
- 将std::thread对象做为数据成员列表项中的最后一个。
Item 38:Be aware of varying thread handle destructor behavior.
条款38:要小心不同的线程句柄析构行为。
Things to Remember
需要记住:
- Future destructors normally just destroy the future’s data members.
- Future的析构函数通常只会销毁future的数据成员。
- The final future referring to a shared state for a non-deferred task launched via std::async blocks until the task completes.
- 涉及到非延期task的共享状态的final future是通过std::async,在task完成后加载的。
Item 39:Consider void futures for one-shot event communication.
条款39: 考虑对于一次性事件通信中使用void future。
Things to Remember
需要记住:
- For simple event communication, condvar-based designs require a superfluous mutex, impose constraints on the relative progress of detecting and reacting tasks, and require reacting tasks to verify that the event has taken place.
- 对于简单的事件通信,基于condvar的设计需要一个多余的互斥量,对检测和响应任务的相应进度施加限制,并且需要响应任务验证事件是否已发生。
- Designs employing a flag avoid those problems, but are based on polling, not blocking.
- 设计使用一个标记来避免这些问题,但这是基于轮询的,而不是基于阻塞的。
- A condvar and flag can be used together, but the resulting communications mechanism is somewhat stilted.
- condvar和标记可以一起使用,但结果通信机制会有点不自然。
- Using std::promises and futures dodges these issues, but the approach uses heap memory for shared states, and it’s limited to one-shot communication.
- 使用std::promises和futures来回避这些问题,但是这种方法使用堆内存来处理共享状态,并且只能用于一次性通信。
Item 40:Use std::atomic for concurrency, volatile for special memory.
条款40:使用std::atomic处理并发,使用volatile处理特殊内存。
Things to Remember
需要记住:
- std::atomic is for data accessed from multiple threads without using mutexes. It’s a tool for writing concurrent software.
- std::atomic用来在不使用mutex的多线程情形下访问数据。它是编写并发软件的一个工具。
- volatile is for memory where reads and writes should not be optimized away. It’s a tool for working with special memory.
- volatile用来在读写操作不是优化的方式下处理内存。它是编写处理特殊内存的一个工具。
CHAPTER 8 Tweaks
章节8 小改进
Item 41:Consider pass by value for copyable parameters that are cheap to move and always copied.
条款41: 考虑使用传值来处理移动操作很廉价而且总是被拷贝的参数(如果移动没有提高性能的话,编译器可能就直接优化成拷贝了)
Things to Remember
需要记住:
- For copyable, cheap-to-move parameters that are always copied, pass by value may be nearly as efficient as pass by reference, it’s easier to implement, and it can generate less object code.
- 对于能够拷贝,移动操作很廉价而且总是被拷贝的参数,传值跟传引用基本上同样高效,而且更容易实现,产生更少的代码。
- Copying parameters via construction may be significantly more expensive than copying them via assignment.
- 通过构造函数拷贝参数可能比通过赋值操作符拷贝参数更加高昂。
- Pass by value is subject to the slicing problem, so it’s typically inappropriate for base class parameter types.
- 传值操作会有切片问题,所以一般对于基类参数类型不适合。
Item 42:Consider emplacement instead of insertion.
条款42:考虑使用emplace的函数,而不是insert函数
Things to Remember
需要记住:
- In principle, emplacement functions should sometimes be more efficient than their insertion counterparts, and they should never be less efficient.
- 原则上,emplace的函数有时应该比插入函数效率更高,而且效率永远不会降低。
- In practice, they’re most likely to be faster when (1) the value being added is constructed into the container, not assigned; (2) the argument type(s) passed differ from the type held by the container; and (3) the container won’t reject the value being added due to it being a duplicate.
- 在实践中,以下情形(emplace的函数)可能更快:(1)要添加的值是构造到容器中时,而不是赋值到容器中(2)传递的参数类型与容器中的类型不同(3)容器不会排斥要添加的值,因为它是重复的值。
- Emplacement functions may perform type conversions that would be rejected by insertion functions.
- Emplace的函数有可能执行类型转换,而insert的函数会排斥。