c++笔记 ---表达式
1. 后自增操作的优先级高于解引用操作,因此 *iter++ 等效于 *(iter++)。 子表达式 iter++ 使 iter 加 1,然后返回 iter 原值的副本作为该表达式的结果。因此,解引用操作 * 的操作数是 iter 未加 1 前的副本。
2. 箭头操作符 (->)
下面的表达式相互等价:
(*p).foo; // dereference p to get an object and fetch its member named foo p->foo; // equivalent way to fetch the foo from the object to which p points
区别:
(*sp).same_isbn(item2); // run same_isbn on object to which sp points
这里,对 sp 进行解引用以获得指定的 Sales_item 对象。然后使用点操作符调用指定对象的 same_isbn 成员函数。在上述用法中,注意必须用圆括号把 解引用括起来,因为解引用的优先级低于点操作符。如果漏掉圆括号,则这段代码的含义就完全不同了:
*sp.same_isbn(item2); // error: sp has no member named same_isbn
这个表达式企图获得 sp 对象的 same_isbn 成员。等价于:
*(sp.same_isbn(item2)); // equivalent to *sp.same_isbn(item2);
3. 条件操作符
1) 避免条件操作符的深度嵌套
2)在输出表达式中使用条件操作符
cout << (i < j ? i : j); // ok: prints larger of i and j cout << (i < j) ? i : j; // prints 1 or 0!
cout << i < j ? i : j; // error: compares cout to int
第二个表达式比较有趣:它将i和j 的比较结果视为 << 操作符的操作数,
输出 1 或 0。 << 操作符返回 cout 值,然后将返回结果作为条件操作符的判
断条件。也就是,第二个表达式等效于:
cout << (i < j); // prints 1 or 0
cout ? i : j; // test cout and then evaluate i or j
// depending on whether cout evaluates to true or false
4.逗号运算符与逗号表达式
- 逗号运算符:C++中,逗号既是分隔符,又是运算符,且优先级最低。
-
逗号表达式:用逗号连接起来的表达式,其一般格式为:
<表达式1>,<表达式2>,…,<表达式n> - 运算规则是:从左到右依次求出各表达式的值,并将最后一个表达式的值当做整个逗号表达式的值。
例如:假定a=1,b=2,c=3; 以下逗号表达式的结果是:
c=b=(a=3,4*3) //结果为:a=3,b=12,c=12,表达式的值为12
c=b=a=3,4*3 //结果为:a=3,b=3,c=3,表达式的值为12
c=(b=a=3,4*3) //结果为:a=3,b=3,c=12,表达式的值为1
5.sizeof 操作符
sizeof有三种语法形式,如下:
1) sizeof( object ); // sizeof( 对象 );
2) sizeof( type_name ); // sizeof( 类型 );
3) sizeof object; // sizeof 对象;
所有指针变量的sizeof 操作结果均为4。
char、signed char和unsigned char的sizeof值为1
sizeof操作符,对变量或对象可以不加括号,但若是类型,须加括号。
sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。如:
sizeof( 2 ); // 2的类型为int,所以等价于 sizeof( int ); sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型,所以等价于 sizeof( double );
sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用
函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值,即下面这些写法都是错误的:
sizeof( foo ); // error
void foo2() { }
sizeof( foo2() ); // error
struct S
{
unsigned int f1 : 1;
unsigned int f2 : 5;
unsigned int f3 : 12;
};
sizeof( S.f1 ); // error
注意:
1. int *p; sizeof(p)=4; 但sizeof(*p)相当于sizeof(int);
对于静态数组,sizeof可直接计算数组大小;
例:
int a[10];char b[]="hello";
sizeof(a)等于4*10=40;
sizeof(b)等于6;
2. 数组做形参时,数组名称当作指针使用!!
void fun(char p[])
{sizeof(p)等于4}
3. 使用sizeof时string的注意事项
string s="hello";
sizeof(s)等于string类的大小,sizeof(s.c_str())得到的是字符串长度。
double* (*a)[3][6];
cout<<sizeof(a)<<endl; // 4 a为指针
cout<<sizeof(*a)<<endl; // 72 *a为一个有3*6个指针元素的数组
cout<<sizeof(**a)<<endl; // 24 **a为数组一维的6个指针
cout<<sizeof(***a)<<endl; // 4 ***a为一维的第一个指针
cout<<sizeof(****a)<<endl; // 8 ****a为一个double变量
既然a是执行double*[3][6]类型的指针,*a就表示一个double*[3][6]的多维数组类型,因此sizeof(*a)=3*6*sizeof(double*)=72。同样的,**a表示一个double*[6]类型的数组,所以sizeof(**a)=6*sizeof (double*)=24。***a就表示其中的一个元素,也就是double*了,所以sizeof(***a)=4。至于****a,就是一个double了,所以sizeof(****a)=sizeof(double)=8。
6. new 和 delete 表达式
动态创建对象时,只需指定其数据类型,而不必为该对象命名。取而代之的是,new 表达式返回指向新创建对象的指针,我们通过该指针来访问此对象:
int i; // named, uninitialized int variable
int *pi = new int; // pi points to dynamically allocated,
// unnamed, uninitialized int
这个 new 表达式在自由存储区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针 pi。
1>. 使用new动态分配内存:若没有足够内存,则new返回0(空值指针null pointer);
2>. 不要使用delete释放不是new分配的内存,delete释放指针指向的内存,但不会删除指针本身;
3>. 对空值指针应用delete是安全的;
4>. 一旦删除了指针所指向的对象,立即将指针置为 0,这样就非常清楚地表明指针不再指向任何对象。
5>. 创建数组时的静态联编与动态联编:数组声名int a[10], 静态联编,数组的长度在编译时确定;
用new[]创建数组,动态联编,运行时为数组分配内存空间。动态-运行时分配内存
动态创建对象的初始化
无论程序是明确地不初始化还是要求进行值初始化,都会自动调用其默认构造函数初始化该对象。而对于内置类型或没有定义默认构造 函数的类型,采用不同初始化方式则有显著的差别
int *pi = new int; // pi points to an uninitialized int 240 int *pi = new int(); // pi points to an int value-initialized to 0
耗尽内存
如果程序用完了所有可用的内存,new 表达式就有可能失败。如果 new 表达式无法获取需要的内存空间,系统将抛出名为 bad_alloc 的异常
const 对象的动态分配和回收
下面三种常见的程序错误都与动态内存分配相关:
1. 删除( delete )指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory leak)”。内存泄漏很难发现,一般需等应用程序运行了一段时间 后,耗尽了所有内存空间时,内存泄漏才会显露出来。
2. 读写已删除的对象。如果删除指针所指向的对象之后,将指针置为 0 值,则比较容易检测出这类错误。
3. 对同一个内存空间使用两次 delete 表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做 delete 运算,将该对象的内存空间返还给自由存储区, 然后接着 delete 第二个指针,此时则自由存储区可能会被破坏。
删除 const 对象
不能改变 const 对象的值,但可撤销对象本身。如同其他动态
对象一样, const 动态对象也是使用删除指针来释放的

浙公网安备 33010602011771号