1.进行初始化时=,(),{}的区别
- 初始化变量一般有以下
3
种写法:int x(0);
int y=0;
int z{0};
(也有int z={0};
这样的写法,但基本等同于int z{0};
)
- 类中非
static
成员变量的初始化可以使用{}
和=
,但是不能使用()
- 不可复制的对象(如
std::atomic
)不能使用{}
和()
进行初始化 - 用
{}
进行初始化的基本类型不允许发生精度下降的隐式转换,比如:int x(1.1);
和int x=1.1;
都是可以的,但x{1.0};
会报错。 - 有的程序员会不小心写出这样的初始化代码
Widget w();
,但实际上这是函数声明,但是Widget w{};
这样的写法则放心得多。 - 对于函数重载,
{}
写法会优先匹配形式参数为std::initializer_list
类型的函数,比如对于vector
的构造函数。std::vector v1(10, 20);
//会生成10
个元素,而且它们的值都是20
。std::vector v2{10, 20};
//会生成2
个元素,而且它们的值分别是10
和20
。
2.尽量使用nullptr而不是0或者NULL
0
是int
类型而不是指针类型,NULL
是long
类型而不是指针类型,nullptr
比较特殊,但可以看做为是指针类型。- 因此如果对于整形和指针类型的函数重置,使用
0
或者NULL
有可能会导致调用了错误的函数而不自知。 nullptr
经常和模板,auto
等类型自动推断机制结合使用。
3.尽量使用alias而不是typedef
- 使函数指针的别名书写更容易写更容易看:
typedef void (*FP)(int, const std::string&);//难看
using FP = void(*)(int, const std::string&);//清晰
- 使别名模板的书写更容易写更容易看:
//难看
template<typename T>
struct MyAllocList{
typedef std::list<T, MyAlloc<T>> type;
};
MyAllocList<Widget>::type lw; //客户代码
//清晰
template<typename T>
using MyAllocList = std::list<T, MyAlloc<T>>;
MyAllocList<Widget> lw; //客户代码
4.尽量使用enum class而不是enum
enum class Suit { Diamonds, Hearts, Clubs, Spades };
void PlayCard(Suit suit)
{
if (suit == Suit::Clubs) // 必须标清枚举类
{ /*...*/}
}
enum Suit { Diamonds, Hearts, Clubs, Spades };
void PlayCard(Suit suit)
{
if (suit == Clubs) // 可以直接写枚举值
{ /*...*/
}
}
- 无范围的
enum
会造成命名空间的污染,带范围的enum class
则无此顾虑。 - 带范围的
enum class
不能隐式转换成整数类型,更加符合语义和规范化 C++11
之后enum
和enum class
都可以明确指出枚举值的类型,如enum class Color : unsigned char { red, blue };
5.尽量使用delete而不是private
- 要取消复制构造函数和赋值构造函数等默认函数的定义,在
C++98
时代我们一般是把它声明为私有函数;但在C++11
中可以使用delete
关键字,如:MyClass(const MyClass&) = delete;
private
只能用于成员函数,delete
可以用于一切函数,如友元函数或者一般函数delete
可以关闭因为隐式转换而造成的函数调用,如bool isLucky(int n); bool isLucky(char) = delete;
- 对于函数模板,可以阻止某些类型参数成功匹配模板并进行函数实例化
6.尽量使用const_iterator而不是iterator
首先声明清楚const_iterator
的概念,iter
本身的值是可以改变的,但是其所指向的元素是不可以被改变的(即需要区分const *::iterator
和*::const_iterator
)。
int main()
{
vector<int> a(5);
*(a.begin()) = 6;//返回的是vector<int>::iterator,不会报错
cout<<a[0];
}
int main()
{
vector<int> a(5);
*(a.cbegin()) = 6;//返回的是vector<int>::const_iterator,编译错误
cout<<a[0];
}