「C++学习笔记」引用、内联函数、auto、范围for、nullptr

目录

一、引用

二、内联函数

三、auto

四、范围for

五、nullptr


一、引用

1.引用的概念

引用可以看成某个变量的别名。

#include <iostream>
using namespace std;

int main()
{
	int x = 1;
	int& y = x;
	cout << x << endl;
	cout << y << endl;

    //引用改变,变量也跟着改变
    y = 2;
	cout << x << endl;
	cout << y << endl;

	return 0;
}

2.引用的一些细节

引用的地址和变量的地址一致

引用必须定义的时候初始化

一个变量可以有多个引用

引用一旦引用一个变量后就不能引用其他变量

#include <iostream>
using namespace std;

int main()
{
	int x = 1;
	int& y = x;
	cout << &x << endl;
	cout << &y << endl;

	return 0;
}

3.常引用

权限可以不变,可以缩小,不可以放大。

//权限不变
int x = 0;
int& y = x;

//权限缩小
int x = 0;
const int& y = x;//常引用

//权限放大
const int x = 0;
int& y = x;

4.引用作为函数参数

#include <iostream>
using namespace std;

void Swap(int& x, int& y)
{
	int temp = x;
	x = y;
	y = temp;
}

int main()
{
	int x = 10;
	int y = 20;
	Swap(x, y);
	cout << "x = " << x << endl;
	cout << "y = " << y << endl;

	return 0;
}

5.引用作为函数返回值

只有当变量所控制的空间出了作用域还没有被释放,才可以使用传引用返回。

#include <iostream>
using namespace std;

int& Add(int x, int y)
{
	int z = x + y;
	return z;
}

int main()
{
    int& sum = Add(1, 2);
	Add(10, 20);
	cout << "1 + 2 = " << sum << endl;

    //可以看到sum是z的引用,但z出了作用域后就被释放了
    //这时候如果输出sum,sum的值是不能确定的
    //也就是说这段程序是错误的!

	return 0;
}

6.引用作为函数参数时的效率

结构体传参时,要用结构体的指针作为函数参数。如果用结构体作为函数参数,当结构体很大时,参数压栈会有比较大的开销,使效率降低。这里我们来比较结构体和结构体引用哪个效率更优:

#include <iostream>
#include <time.h>
using namespace std;

struct A
{
	int data[2000];
	int size;
};

//使用结构体作为函数参数
void F1(struct A a)
{
	a.size = 0;
}

//使用结构体引用作为函数参数
void F2(struct A& a)
{
	a.size = 0;
}

int main()
{
	struct A a = { {0}, 0 };
	int64_t i = 0;

	int64_t start1 = clock();
	for (i = 0; i < 100000000; ++i)
	{
		F1(a);
	}
	int64_t end1 = clock();

	int64_t start2 = clock();
	for (i = 0; i < 100000000; ++i)
	{
		F2(a);
	}
	int64_t end2 = clock();

	cout << end1 - start1 << endl;
	cout << end2 - start2 << endl;

	return 0;
}

我的环境是vs2022,cpu是i5-10210U,每秒可以执行...嗯...很多很多条机器指令( o(* ̄▽ ̄*)o),在Release版本下,程序运行结果是:使用结构体作为函数参数需要花费120ms左右的时间,而使用结构体引用作为函数参数需要花费不到0ms的时间,所以使用引用效率更好。

7.引用作为函数返回值时的效率

#include <iostream>
#include <time.h>
using namespace std;

struct A
{
	int data[2000];
	int size;
};

//使用结构体作为函数返回值
struct A F1(struct A a)
{
	a.size = 0;
	return a;
}

//使用结构体引用作为函数返回值
struct A& F2(struct A a)
{
	a.size = 0;
	return a;
}

int main()
{
	struct A a = { {0}, 0 };
	int64_t i = 0;

	int64_t start1 = clock();
	for (i = 0; i < 1000000; ++i)
	{
		F1(a);
	}
	int64_t end1 = clock();

	int64_t start2 = clock();
	for (i = 0; i < 1000000; ++i)
	{
		F2(a);
	}
	int64_t end2 = clock();

	cout << end1 - start1 << endl;
	cout << end2 - start2 << endl;

	return 0;
}

Release版本下,使用结构体作为函数返回值需要花费190ms左右的时间,使用结构体引用作为函数返回值需要花费120ms左右的时间,故使用引用返回效率更好。

细心的朋友可能发现了函数F1、F2中都有一句不痛不痒的a.size = 0,这是为了对抗编译器的优化。实际上,现在的编译器都非常聪明,如果不写a.size = 0,当调用函数的时候,编译器发现这个函数啥也没干,直接就给优化掉了,还想调用?不存在的,结果就是,无论循环多少遍,运行时间都是0。而平时我们肯定不会写这么无聊的函数,所以如果可以的话,使用引用作为函数的返回值是很有意义的!

8.引用与指针的区别

引用的底层是用指针实现的

	int x = 0;

	int& rx = x;
	rx = 1;

	int* px = &x;
	*px = 1;

我们对这段代码进行反汇编:

可以看到,引用和指针的汇编语言是一样的,但它们俩还是有一定区别的:

引用在定义的时候必须初始化,指针不用。

无空引用,有空指针。

无多级引用,有多级指针。

引用在引用一个变量后,不能改变,指针在指向一个变量后,可以改变。

sizeof(引用)的结果由所引用的变量类型决定,sizeof(指针)的结果由机器字长(常见的有32位和64位)决定。

二、内联函数

1.内联函数的使用

//使用inline修饰的函数就是内联函数
inline int Add(int x, int y)
{
	return x + y;
}

int main()
{
	Add(1, 2);
	return 0;
}

2.内联函数的一些细节

内联函数只是我们向编译器发送的一个请求,编译器可以忽略这个请求。如果编译器同意了这个请求,则会在编译阶段把函数调用替换成函数体,如此一来就省去了函数调用的开销,提高了程序的运行效率,但可能会使编译后的可执行文件体积变大。

对于逻辑简单,代码量小,频繁调用,且没有递归的函数可以考虑使用内联函数。

内联函数的声明和定义不能分离,否则会导致链接错误。

三、auto

1.auto的使用

C++11中,auto定义的变量由编译器在编译时自动推导出其类型,且auto定义的变量必须初始化

//i的类型为int,c的类型为char
auto i = 0;
auto c = '!';

2.auto的一些细节

auto不能定义函数参数

auto不能定义数组

auto对指针与引用的识别

#include <iostream>
using namespace std;

int main()
{
	//y和z的类型都是int*
	int x = 0;
	auto y = &x;
	auto* z = &x;
	cout << y << endl;
	cout << z << endl;

	//要想识别为引用,必须带&
	int a = 0;
	auto& b = a;
	cout << &a << endl;
	cout << &b << endl;

	return 0;
}

四、范围for

范围for的使用

#include <iostream>
using namespace std;

int main()
{
	int arr[100] = { 0 };
	for (auto& i : arr)
	{
		i = 1;
	}
	for (auto i : arr)
	{
		cout << i;
	}
	cout << endl;
	return 0;
}

五、nullptr

nullptr的由来

既然都有NULL了,为什么还会有nullptr呢?在C语言的stddef.h中我们可以看到对NULL的解释(NULL - cppreference.com):

可以看到,在C++中,NULL可能会被宏定义为值为0的整数常量表达式,而我们期望NULL代表的意思是指针空值(void*)0,所以C++11起引入关键字nullptr,并规定关键字nullptr代表指针空值!

C++官方文档对nullptr的解释(nullptr ,指针字面量 - cppreference.com):

 C++官方文档网址:cppreference.com

最后,分享一张好看的图片(´・ ᴗ ・`)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值