在模板类型推导时,有引用的实参会被视为无引用,他们的引用会被忽略
对于通用引用的推导,左值实参会被特殊对待
对于传值类型推导,const和/或volatile实参会被认为是non-const的和non-volatile的
在模板类型推导时,数组名或者函数名实参会退化为指针,除非它们被用于初始化引用
.**理解auto类型推导auto类型推导通常和模板类型推导相同,但是auto类型推导假定花括号初始化代表std::initializer_list,而模板类型推导不这样做
在C++14中auto允许出现在函数返回值或者lambda函数形参中,但是它的工作机制是模板类型推导那一套方案,而不是auto类型推导
.**理解decltypedecltype总是不加修改的产生变量或者表达式的类型。
对于T类型的不是单纯的变量名的左值表达式,decltype总是产出T的引用即T。
C++14支持decltype(auto),就像auto一样,推导出类型,但是它使用decltype的规则进行推导。
4.学会查看类型推导结果类型推断可以从IDE看出,从编译器报错看出,从BoostTypeIndex库的使用看出
这些工具可能既不准确也无帮助,所以理解C++类型推导规则才是最重要的
第二章Auto5.**优先考虑auto而非显式类型声明auto变量必须初始化,通常它可以避免一些移植性和效率性的问题,也使得重构更方便,还能让你少打几个字。
正如Item和6讨论的,auto类型的变量可能会踩到一些陷阱。
6.**auto推导若非己愿,使用显式类型初始化惯用法不可见的代理类可能会使auto从表达式中推导出“错误的”类型
显式类型初始器惯用法强制auto推导出你想要的结果
第三章移步现代C++7.**区别使用()和{}创建对象括号初始化是最广泛使用的初始化语法,它防止变窄转换,并且对于C++最令人头疼的解析有天生的免疫性
在构造函数重载决议中,括号初始化尽最大可能与std::initializer_list参数匹配,即便其他构造函数看起来是更好的选择
对于数值类型的std::vector来说使用花括号初始化和小括号初始化会造成巨大的不同
在模板类选择使用小括号初始化或使用花括号初始化创建对象是一个挑战。
8.**优先考虑nullptr而非0和NULL优先考虑nullptr而非0和NULL
避免重载指针和整型
9.优先考虑别名声明而非typedefstypedef不支持模板化,但是别名声明支持(using...)。
别名模板避免了使用“::type”后缀,而且在模板中使用typedef还需要在前面加上typename
C++14提供了C++11所有typetraits转换的别名声明版本
10.**优先考虑限域enum而非未限域enumC++98的enum即非限域enum。
限域enum的枚举名仅在enum内可见。要转换为其它类型只能使用cast。
非限域/限域enum都支持底层类型说明语法,限域enum底层类型默认是int。非限域enum没有默认底层类型。
限域enum总是可以前置声明。非限域enum仅当指定它们的底层类型时才能前置。
11.优先考虑使用deleted函数而非使用未定义的私有声明比起声明函数为private但不定义,使用deleted函数更好
任何函数都能被删除(bedeleted),包括非成员函数和模板实例(译注:实例化的函数)
1.**使用override声明重写函数为重写函数加上override
成员函数引用限定让我们可以区别对待左值对象和右值对象(即this)
1.**优先考虑const_iterator而非iterator优先考虑const_iterator而非iterator
在最大程度通用的代码中,优先考虑非成员函数版本的begin,end,rbegin等,而非同名成员函数
14.**如果函数不抛出异常请使用noexceptnoexcept是函数接口的一部分,这意味着调用者可能会依赖它
noexcept函数较之于non-noexcept函数更容易优化
noexcept对于移动语义,swap,内存释放函数和析构函数非常有用
大多数函数是异常中立的(译注:可能抛也可能不抛异常)而不是noexcept
15.**尽可能的使用constexprconstexpr对象是const,它被在编译期可知的值初始化
当传递编译期可知的值时,constexpr函数可以产出编译期可知的结果
constexpr对象和函数可以使用的范围比non-constexpr对象和函数要大
constexpr是对象和函数接口的一部分
16.**让const成员函数线程安全确保const成员函数线程安全,除非你确定它们永远不会在并发上下文(concurrentcontext)中使用。
使用std::atomic变量可能比互斥量提供更好的性能,但是它只适合操作单个变量或内存位置。
17.理解特殊成员函数的生成特殊成员函数是编译器可能自动生成的函数:默认构造函数,析构函数,拷贝操作,移动操作。
移动操作仅当类没有显式声明移动操作,拷贝操作,析构函数时才自动生成。
拷贝构造函数仅当类没有显式声明拷贝构造函数时才自动生成,并且如果用户声明了移动操作,拷贝构造就是delete。拷贝赋值运算符仅当类没有显式声明拷贝赋值运算符时才自动生成,并且如果用户声明了移动操作,拷贝赋值运算符就是delete。当用户声明了析构函数,拷贝操作的自动生成已被废弃。
成员函数模板不抑制特殊成员函数的生成。
18.**对于独占资源使用std::unique_ptrstd::unique_ptr是轻量级、快速的、只可移动(move-only)的管理专有所有权语义资源的智能指针
默认情况,资源销毁通过delete实现,但是支持自定义删除器。有状态的删除器和函数指针会增加std::unique_ptr对象的大小
将std::unique_ptr转化为std::shared_ptr非常简单
19.**对于共享资源使用std::shared_ptrstd::shared_ptr为有共享所有权的任意资源提供一种自动垃圾回收的便捷方式。
较之于std::unique_ptr,std::shared_ptr对象通常大两倍,控制块会产生开销,需要原子性的引用计数修改操作。
默认资源销毁是通过delete,但是也支持自定义删除器。删除器的类型是什么对于std::shared_ptr的类型没有影响。
避免从原始指针变量上创建std::shared_ptr。
0.**当std::shard_ptr可能悬空时使用std::weak_ptr用std::weak_ptr替代可能会悬空的std::shared_ptr。
std::weak_ptr的潜在使用场景包括:缓存、观察者列表、打破std::shared_ptr环状结构。
1.**优先考虑使用std::make_unique和std::make_shared而非new和直接使用new相比,make函数消除了代码重复,提高了异常安全性。对于std::make_shared和std::allocate_shared,生成的代码更小更快。
不适合使用make函数的情况包括需要指定自定义删除器和希望用花括号初始化。
对于std::shared_ptrs,其他不建议使用make函数的情况包括(1)有自定义内存管理的类;()特别