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+B
C严格按照结合律和优先级运算;但是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];