Effective Modern C++ 笔记(二)——写法规范

1.进行初始化时=,(),{}的区别

  • 初始化变量一般有以下3种写法:
    1. int x(0);
    2. int y=0;
    3. 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个元素,而且它们的值分别是1020

2.尽量使用nullptr而不是0或者NULL

  • 0int类型而不是指针类型,NULLlong类型而不是指针类型,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之后enumenum 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];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值