转向Modern C++
优先使用auto推导类型而非显示类型声明
auto变量需要在声明时进行初始化
int x1; // 未初始化的int变量,值的不确定的,可能为0,也可能是别的值
auto x2; // 错误,需要初始化
auto x3 = 0; // 完美
auto使变量的声明变得简单,甚至仅仅被编译器知道的类型
auto dereUPLess = [](const std::unique_ptr<Widget>& p1,
const std::unique_ptr<Widget>& p2)
{ return *p1 < *p2; }
auto可以避免类型的截断
std::vector<int> vec;
unsigned sz = vec.size(); // size()的返回类型是std::vector<int>::size_type,32位机器上,unsigned和std::vector<int>::size_type都是32bit的,然而64位机器上,unsigned是32bit的,std::vector<int>::size_type却是64bit的,这回导致返回类型的截断
auto sz = vec.size(); // sz的类型是std::vector<int>::size_type,不会导致截断
总结
auto是一个可选项,不是必须项。如果根据你的专业判断,使用显式的类型声明比使用auto会使你的代码更加清晰或者更好维护,或者在其他方面更有优势, 你可以继续使用显式的类型声明。这是一个新人易学,老人已用的新特性。
优先使用nullptr而不是0或者NULL
0字面上是一个int类型,而不是指针。C++扫描到一个0,但是发现在上下文中仅有一个指针使用了它,于是编译器勉强将0解释为空指针。NULL也是同样的道理。
nullprt不在是一个整数类型,它是一个std::nullptr_t类型,std::nullptr_t类型可以隐式的转换为任何原始的指针类型,因此可以认为nullptr指向任何类型的指针。
nullptr可以提高代码的清晰度
auto retTpype = find();
if (retTpype == 0)
{
/* code */
}
if (retTpype == nullprt)
{
/* code */
}
使用nullptr就没有歧义了,也能明显的看出retTpype是一个指针类型。
有限使用别名而不是typedef
typedef void (*FP)(int, const std::string);
using FP = void(*)(int, const std::string);
在所有能使用typedef的地方都可以使用别名,但是typedef不支持模板化,而别名支持
模板别名避免了::type后缀,在模板中,typedef还经常要求使用typename
使用作用域限制的enum而不是无作用域的enum
有作用域限制的enum可以减少命名空间的污染
enum ColorNoScoped
{
black, white, red
};
auto white = false; // 错误,因为white在此作用域中已经被定义
enum class ColorScoped
{
black, white, red
};
auto white = false; // 可以
ColorScoped c = ColorScoped::white;
auto cw = ColorScoped::white;
有作用域限制的enum可以避免一些无必要的隐式类型转换
enum ColorNoScoped
{
black, white, red
};
ColorNoScoped c = red;
if (c < 14.5)
{
/* code */ // 可以
}
enum class ColorScoped
{
black, white, red
};
auto c = ColorScoped::white;
if (c < 14.5) // 错误
{
/* code */
}
if (static_cast<double>(c) < 14.5) // 正确
{
/* code */
}
有作用域限制的enum可以被提前声明,而无作用域限制的enum不可以
enum ColorNoScoped; // 错误
enum class ColorScoped; // 可以
优先使用delete关键字删除函数而不是private而不不实现的空函数
template <class charT, class traits = char_traits<charT> >
class basic_ios : public ios_base {
public:
basic_ios(const basic_ios& ) = delete;
basic_ios& operator=(const basic_ios&) = delete;
/* code */
};
使用override关键字声明覆盖函数
对于派生类中覆盖体都声明为 override,不仅仅可以让编译器在应该要去覆盖基类中函数而没有去覆盖的时候可以警告你。它还可以帮助你预估一下更改基类里的虚函数的标识符可能会 引起的后果。
优先使用const_iterator而不是iterator
std::std::vector<int> values;
auto it = std::find(values.cbegin(), values.cend(), 16);
values.insert(it, 32);