const、inline、nullptr的使用
目录
1.const引用
1.1权限的放大
1.2权限的缩小
2.inline
3.nullptr
1.const引用
可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访 问权限在引用过程中可以缩小,但是不能放大。
不需要注意的是类似 int& rb = a*3; double d = 12.34; int& rd = d; 这样一些场 景下a*3的和结果保存在一个临时对象中, int& rd = d 也是类似,在类型转换中会产生临时对 象存储中间值,也就是时,rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里 就触发了权限放大,必须要用常引用才可以。
所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象, C++中把这个未命名对象叫做临时对象。
1.1权限的放大
int main() {
//权限的放大,a只能读值,不能更改,当取a的别名时,b可读值与改值,会报错
const int a = 10;
//int& b = a;
const int& b = a;//这种写法为正确
return 0;
}
1.2权限的缩小
int main() {
// 这⾥的引⽤是对b访问权限的缩⼩
int b = 20;
const int& rb = b;
return 0;
}
注:在之后的编写中,只能出现权限的缩小,不能出现权限的放大
2.inline
用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联 函数就需要建立栈帧了,就可以提高效率。
inline对于编译器而言只是一个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展 开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁 调用的短小函数,对于递归函数,代码相对多小些的函数,加上inline也会被编译器忽略。
C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不方便调 试,C++设计了inline目的就是替代C的宏函数。
vs编译器 debug版本下面默认是不展开inline的,这样方便调试,debug版本想展开需要设置⼀下 以下两个地方。
inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地 址,链接时会出现报错。
inline(内敛函数)与宏函数类似
#include<iostream>
using namespace std;
//#define ADD(a, b) ((a) + (b))宏函数
inline int Add(int x, int y)
{
int ret = x + y;
ret += 1;
ret += 1;
ret += 1;
return ret;
}
int main()
{
// 可以通过汇编观察程序是否展开
// 有call Add语句就是没有展开,没有就是展开了
int ret = Add(1, 2);
cout << Add(1, 2) * 5 << endl;
return 0;
}
编写上面代码,会显示报错,是因为inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。
此时我们需要下方操作:
3.nullptr
NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:
# ifndef NULL# ifdef __cplusplus# define NULL 0# else# define NULL ((void *)0)# endif# endif
C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量。不论采取何种 定义,在使用空值的指针时,都不可避免的会遇到⼀些麻烦,本想通过f(NULL)调⽤指针版本的 f(int*)函数,但是由于NULL被定义成0,调⽤了f(int x),因此与程序的初衷相悖。f((void*)NULL); 调用会报错。
C++11中引入nullptr,nullptr是⼀个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换 成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被 隐式地转换为指针类型,而不能被转换为整数类型。
#include<iostream>
using namespace std;
void f(int x)
{
cout << "f(int x)" << endl;
}
void f(int* ptr)
{
cout << "f(int* ptr)" << endl;
}
int main()
{
f(0);
// 本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(int
x),因此与程序的初衷相悖。
f(NULL);
f((int*)NULL);
// 编译报错:error C2665: “f”: 2 个重载中没有⼀个可以转换所有参数类型
// f((void*)NULL);
f(nullptr);
return 0;
}
nullptr大大减少了我们对null指针访问报错的风险!!!!