《c++ primer》学习笔记 第五章 表达式

c++ primer》学习笔记 第五章 表达式

注:此次为重读c++ primer,因而主要记录本人易遗忘且相对含糊的知识点,此系列只是个人笔记,读者请勿照搬,建议阅读原书为最佳。

位操作符

位移操作符将其整数操作数视为二进制位的集合,为每一位提供检验和设置的功能。另外,这类操作符还可用于bitset类型的操作数,该类型具有这里所描述的整形操作数的行为。

位操作符共有5个: 取反;<< 左移;>>右移;位与;位异或;位或;

位操作的整数可以是有符号的或无符号的,由于有符号的整数的位操作结果取决于机器,因此强烈建议位操作只应用于unsigned整数。

左移(<<)在右边插入0以补充空位。右移(>>),对于unsigned整数,从左边开始插入0;对于有符号数,则插入符号位的副本或者0值,如何实现视具体情况而定。右移操作数不可以是负数,而且必须是严格小于做操作数的值,否则,结果未定义。

例: bitset<30> b1;

unsigned long ival=0;

若要设置第27位的值为1,则有:

b1.set(27);

ival |= 1ul<<27;

二者等价。实际上,bitset操作比底层的位操作效率更高且更易于理解,因此尽量使用bitset操作。

2 ++i 和 i++

++i是先+1返回i对象本身后在运算,是左值。

i++是先对i进行运算,后执行+1操作,是右值。

int i = 0, j;

j = ++i; // j = 1, i = 1: prefix yields incremented value

j = i++; // j = 1, i = 2: postfix yields unincremented value

为什么推荐使用++i不使用i++?因为++i只需返回+1后的结果即可,而i++必须先保存i当前的值作为操作数。对于int型对象和指针,编译器可优化掉这项额外的工作,但是对于复杂的迭代器类型,这种额外的工作可能会花费更大的代价。因此,从性能方面考虑,尽量使用++i的方式,而只在必要的时候使用i++方式。如:

vector<int> ivec;

int cnt = 10; //10,9,8.....1放到vector

while(cnt > 10)

ivec.put_back(cnt--);

在这里需要使用cnt--,因为必须返回cnt1之前的值才能得到10,如果使用--cnt,加入vector中的就是9,8,7.,,,0.

在单个表达式中组合使用解引用和自增操作符

vector<int>::iterator it = ivec.begin();

while(it != ivec.end())

cout<<*it++<<endl;

由于自增操作的优先级高于解引用操作,因此*it++等价于*it++,it+1,然后返回it原值的副本进行解引用,所以应该是it+1前的副本。

3 sizeof操作符

sizeof操作符返回一个对象或类型名的长度,返回值类型未size_t,长度单位为字节。

sizeof引用在表达式exp上,将获得该表达式的结果的类型长度。

对于sales_item item, *p;

以下三条语句的意义相同,均为返回sales_item的长度。

sizeof(sales_item);

sizeof item;

sizeof *p;

sizeof求数组元素个数:

int sz = sizeof(ia)/sizeof(*ia);

野指针

c++中,删除零值指针是安全的!如果指针的值为0,在其上做delete操作是合法的,但是没有意义。

int *pi = 0;

delete pi; // ok

delete p;之后,p变成没有定义,在很多机器上,尽管p没有定义,但仍然指向它之前指向对象的地址,然而p所指向的内存已经被释放,因此p不再有效。

一旦删除了指针所指向的对象,立即将指针置为0,这样p将不再指向任何对象,防止野指针引发的程序错误。

 

动态内存管理三种常见的出错原因;

1. 删除(delete)指向动态分配的内存的指针失败,造成内存泄露。

2. 读写已删除的对象。将删除的指针置零,可以避免这类错误。

3. 对同一内存空间使用两次delete操作。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做delete,将该对象的内存空间返还给自由存储区,那么接着delete第二个指针,此时自由存储区可能会被破坏。

类型转换

c++的类型转换分为两种:隐式转换和显式转换。

隐式转换主要是基本类型间,做算术或逻辑操作符的转换。如intdoubleintbool等。

显式转换也成为强制类型转换,有四个操作符:static_cast, dynamic_cast, const_castreinterpret_cast.

static_cast: 一般用于基本数据类型之间的强制转换.

int ival; double dval;

ival *= static_cast<int>dval;

这样,现将dval转换为int之后再与ival相乘。如果没有显示转换,则是现将ival转换成double,然后与dval相乘得到double的结果,再讲该结果转换成int赋值给ival

dynamic_cast支持运行时识别指针或引用所指向的对象。一般用于对指针或类对象之间的转换。

const_cast转换表达式的const属性,只用来添加或删除const属性。

reinterpret_cast: 为操作数的位模式提供较低层次的转换。reinterpret_cast依赖于机器,是不安全的,尽量不用。

建议:避免使用强制类型转换。一个设计合理的系统应该是不怎么需要强转的,特别是reinterpret_castconst_cast。而对于static_castdynamic_cast,除非能够确定转换的安全性,否则也不宜多用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值