表达式
左值和右值
使用关键字decltype时,左值和右值有所不同。举例说明,假定p的类型时int*,因为解引用运算符生成左值,所以decltype(* p)的结果时int&。另一方面,因为取地址运算生成右值,所以decltype(&p)的结果是int**,即一个指向整型指针的指针。
求值顺序
有些运算符如<<没有指定执行顺序,没有明确规定何时以及如何对运算对象求值,下面输出表达式的结果可能是 1 1 或者是 0 1 甚至是完全不同的操作,所以代码程序是错误的。
int i = 0;
cout<< i << " " << ++i << endl; //未定义
处理复合表达式
1、拿不准的时候最好用括号来强制让表达式的组合关系符合程序逻辑的要求。
2、如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象。
布尔值不应参与运算
对大多数运算符来说,布尔类型的运算对象将被提升为int类型,布尔变量b的值为真,参与运算时将被提升为整数值1,求负后结果时-1。将-1再转回布尔值并将其作为b2的初始值,显然这个初始值不等于0,转换成布尔值后应该为1,所以b2为真。
bool b = true;
bool b2 = -b; // b2是true
递增递减运算符
除非必须,否则不用递增递减运算符的后置版本,即使用 ++i 而非 i++ 。
auto pbeg = v.begin();
while(pbeg != v.end() && *pbeg >= 0)
cout << *pbeg++ << endl;
成员访问
ptr->mem 等价于 (*ptr).mem。
string s1 = "a string", *p = &s1;
auto n = s1.size();
n = (*p).size(); // 若 n = *p.size()则错误
n = p->size();
条件运算符
finalgrade = (grade > 90) ? "high pass"
: (grade < 60) ? "fail" : "pass";
cout << ((grade < 60) ? "fail" : "pass"); // 注意要加上括号
sizeof运算符
在sizeof的运算对象中解引用一个无效指针仍然是一种安全的行为,因为指针并没有被真正使用。
constexpr size_t sz = sizeof(ia)/sizeof(*ia); // ia为数组,返回ia的元素数量
int arr[sz]; // 正确,sz为常量表达式
显式转换
强制类型转换有static_cast、dynamic_cast、const_cast、reinterpret_cast。
static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
告诉编译器不在于精度损失,警告信息将关闭。可以用来找回存在于void*指针中的值,但应确保转换后所得的类型就是指针所指的类型,一旦不符将产生未定义的后果。
double slope = static_cast<double>(j)/i;
void* p = &d;
double *dp = static_cast<double*>(p);
const_cast
只能改变运算对象的底层const,去掉const性质。只有const_cast能改变表达式的常量属性。
const char *pc;
char *p = const_cast<char*>(pc); // 正确,但通过p写值是未定义行为
const char *cp;
char *q = static_cast<char*>(cp); // 错误,static_cast不能转换掉const性质
static_cast<string>(cp); // 正确,字符串字面值转换成string类型
const_cast<string>(cp); // 错误,const_cast只改变常量属性
reinterpret_cast
通常为运算对象的位模式提供较低层次上的重新解释。使用它是非常危险的。
int *ip;
char *pc = reinterpret_cast<char*>(ip); // pc所指的真实对象是int而非char
string str(pc); // 错误,pc不是字符指针
语句
空语句
使用空语句应该加上注释,从而令读这段代码的人知道该语句是有意省略的。
检测空格、制表符、换行符等
// 此处的std::noskipws表示的是不忽略任何地方的空白(包括制表符和空格等)
while (cin >> std::noskipws >> cval)
{ ... }
while(cin)
#include <iostream>
using namespace std;
void main()
{
do
{
int v1, v2;
cout << "Please enter two numbers to sum:";
if (cin >> v1 >> v2)
cout << "Sum is : " << v1 + v2 << endl;
}
while (cin);
}
try throw catch
#include <iostream>
#include <stdexcept> //标准异常库
using namespace std;
void main()
{
int a,b;
cout << "请输入相除的两个整数:";
while (cin >> a >> b)
{
try
{
if (b == 0)
throw runtime_error("被除数不能为零");
cout << static_cast<double>(a) / b << endl;
cout << "请输入相除的两个整数:";
}
catch (runtime_error err)
{
cout << err.what(); // 实例的成员函数,返回内容由编译其决定
cout << "\n是否需要重新输入? Enter y or n:" << endl;
char c;
cin >> c;
if (!cin || c == 'n')
break; //break只能用在开关体或者循环体中
}
//try是检测异常的,如果产生了异常,就throw(抛出)一个异常,然后被catch到,进行异常的处理
//如果没有catch部分,仅有try,仍然会报错
}
}