1.运算符的运算顺序
1.1 有运算顺序
只有4种: 逻辑与、逻辑或、条件运算符、逗号运算符
因此,这四种运算符的运算表达式多复杂,均按照指定的顺序,依次执行每个位置的表达式。
1.2 无运算顺序的
实际情况:求值按顺序(优先级、结合律),但是求因子没顺序!!!
存在问题:同一个对象参与多个因子的求取,没法保证该对象的纯洁性
解决方案:加括号
例子:
int a = 0;
int *p = &a;
int b = f(p)+g(p)*h(p);
上述例子:可以转化为int b = A+BC;A=f(p);B=g(p);C=h(p);
实际情况:A+BC严格按照结合律和优先级运算;但是ABC的求取过程没有顺序,即函数fgh的执行顺序不固定
存在问题:因为fgh三个对同一个对象p执行了操作,没法保证原本的假设;
解决方案:严格加括号,比如:int b = f(p)+((g(p))*h(p));这样计算顺序就变成了:ghf了
2.相等性测试与布尔字面值
箴言:除非比较的对象是布尔对象,否则不要用布尔字面值true和false作为比较对象
原因:bool与int参与运算,会提升为int
推荐:使用第一种例子
例子一:推荐
if(val){}
if(!cal){}
例子二:摒弃
if(true == val){}
例子三:
if(1 == val){}
第二种与第三种实际上是一样的,所以只有当val=1的时候,例子23才会成立,尽管val=2也不会成立
注意:
当然,如果项目组中宏定义了:#define TRUE (1 ),是可以使用的,这里说的不能参与比较的是c++自带的true(这里true=1,2,3,,,)
3. ++i优于i++
原因:
++i:加1;返回结果值;保存加1值;
i++:保存原值;加1;返回结果值;保存加1值;
由此可见:如果我们不需要修改前的值,那么后置版本的操作就是一种浪费。
对于整型和指针类型来说,编译器会对这种额外工作进行优化;但是对于相对复杂的迭代器类型,这种额外的工作就消耗巨大了。
4. 运算对象可按任意顺序求值
常见错误案例:将所有字符变为大写
while (beg != s.end() && !isspace(*beg)){
*beg = toupper(*beg++);//错误:该赋值语句未定义
}
存在问题:赋值运算符左右两端的运算对象都用到了beg,并且右侧的对象还改变了beg的值,所以该赋值语句是未定义的。
正确案例:把解引用和递增分为两项任务来完成
for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it){
*it = toupper(*it);
}
5. 成员访问运算符
ptr->mem 等价于 (*ptr).mem
string s1 = "a string";
string *p = &s1;
n = (*p).size();
n = p->size();
6. 条件运算符最好加括号
A? B:C最好改成 ((A)?B:C)
原因:选择运算符的优先级比较低,如果不加括号的话,有可能被周边的运算符肢解!!!
cout << ((grade < 60)? "fail" : "pass") << endl;//输出pass或者fail
cout << (grade < 60)? "fail" : "pass" << endl; //输出1或者0
cout << grade < 60? "fail" : "pass" << endl; //错误:试图比较cout和grade<60
第二条语句等价于
cout << (grade < 60); //输出1或0到cout
cout ? "fail" : "pass"; //根据cout的值是true或false产生对应的字面值
第三条语句等价于
cout << grade; //小于运算符的优先级低于移位运算符,所以先输出grade到cout
cout < 60 ? "fail" : "pass";//然后比较cout和60
7. 移位运算符的妙用
检测某一个bit位是1还是0
bool status = quzz & (1UL << 27);//quzz的第27bit位是1还是0
第二条语句等价于
cout << (grade < 60); //输出1或0到cout
cout ? "fail" : "pass"; //根据cout的值是true或false产生对应的字面值
第三条语句等价于
cout << grade; //小于运算符的优先级低于移位运算符,所以先输出grade到cout
cout < 60 ? "fail" : "pass";//然后比较cout和60
8. sizeof运算符
- 对char或者类型为char的表达式执行sizeof,结果为1;
- 对数组执行sizeof,得到该数组所占的空间大小;
- 对string和vector执行sizeof,返回该对象的固定容器的字节数,并非当前元素个数的字节数;
//根据数组a的大小,重新定义一个数组b
constexpr size_t sz = sizeof(a)/(*a);//这里用到了constexpr 哟!
int b[sz];