静态断言 static_assert
关于断言的个人理解
先说一下为什么要使用断言。在第一次见到断言时就很疑惑,为什么要使用断言,比如指针为NULL(assert(ptr!=NULL)
),可以先判断是否为NULL然后返回嘛,可以用异常机制包起来嘛。
目前的理解是断言就是为了检查源码逻辑而存在的,跟其它检错机制有些目的上的差别。比如在一个类中写了一个mynew()函数,和一个mydelete(),对某个私有指针变量赋值。此处有个不变的逻辑是必须先调用一个mynew(),才能再执行一个mydelete()。如果我只写个几千来行不到十个类的项目,我可能有这个自信能保证不会用错。但是代码规模再大一些的话,这个自信程度就要缩水了。
回到第一段的问题,这个时候用判断返回有什么问题,如果这么做的话的确保证了代码不会运行错误,但是其实隐藏了我此处的逻辑错误必须先调用一个mynew(),才能再执行一个mydelete()*,显然我没有按照这个逻辑执行才会出现错误,此时直接判断返回会掩盖掉逻辑问题(日志另说),因为这个错误可能是由其他逻辑错误导致的子问题,我需要做的是检查源码,而不是忽略这个问题。
而使用异常处理,当然也不会让程序崩溃,但是对用户来说他是没办法解决问题的,用户没办法去修改代码里面的逻辑问题,让这个内存得到正确的释放。异常处理适用于处理逻辑上可能发生的“错误”,比如用户没有按照你要求的顺序操作等。
总结一下断言是给程序员自检逻辑时候用的(排除逻辑上不可能出现的状态,如果出现了,你的代码逻辑有问题),不是给用户用的,也不是用来检查输入正确性的。还有日志如果这么使用的话,其实和断言的作用一样,不过断言是在编写时候使用,而日志一般是项目发布后,用来检测错误和运行状态的。
static_assert
assert是在运行时检查的,如果代码没有运行到你写那部分的话,自然也就没有用到这句断言。 static_assert 则是在编译期间调用,可以使用在函数内或函数体外(建议)。 显然由于其是在编译期间使用,所以里面填写的表达式必然无法使用变量,举个简单例子
assert_static(sizeof(int)!=4,"该程序需要运行在32位机上"); //正确写法
int n=10;
assert_static(n>0,"整数n应该大于0"); //错误写法,不要使用变量
其他
1.书中这节给出的枚举类(按位定义)判断重复的小技巧可以记一下(所以枚举变量取或和最大标志判断是否相等)
2.断言头文件为 #include<cassert>
快速初始化成员变量
vs2012没有支持。
非静态成员的sizeof
class Dog{
public:
int age;
};
void main(){
cout<<sizeof(Dog::age)<<endl; //C++ 11 支持 c++98不支持
cout<<sizeof((People*)0->age)<<endl; //c++98中的技巧 空指针“实例化”一个对象
}
friend语法
略微调整,友元类声明是不需要加class关键字了。导致可以写出以下的模板类:
temple<typename T> class HelloClass{
public :
friend T;
private:
//其他内容...
}
有什么用? 我可以指定任意“好友”类来随便玩弄我的私有变量了[doge],书中解释是可以方便测试,私有变量直接”点“出来,总是比写一堆getter,setter方法来的方便(特别是你的IDE没办法自动生成的时候…)。而发表版本可以传入一个int之类的内置类型时,这句话友元声明就无效了。
final/override 关键字
1.final关键字可以终止子类继续重载虚函数,“爸爸的定的规矩不是你能改的”父类如是说。
class Base{
virtual void fun() = 0; //纯虚函数
virtual void fun1();
};
clase Child1:public Base{
void fun() final; //在别处实现
};
clase Child11:public Child1{
void fun(); //编译不通过
void fun11( ) override;
};
2.override
明确的指出了重载操作。比如上例中的孙子Child想重载fun1,结果手抖多打个1,变成fun11。编译时会说你这不是重载不给过。如果没有这个关键字的话,编译过了,但其实并没有重载fun1而是定义一个新函数fun11,调用fun1的时候其实调用的是父类(或往上实现了该方法的类)的函数内容,导致莫名其妙的问题出现。除了名字拼错外,还有添加参数等,反正不是重载但是加了override关键字的都是错、错、错。