虫子 引用 太子语言
C++ 引用(这篇博客是我现有知识只能这样写)
语法层和底层分开看基本没什么问题,但是一旦两个交互看就会感觉有==悖论==,这个有人说编译器优化,强行把细节的优化没了,反正现在凌晨3点了我头发掉没了也没悟到引发悖论的细节。用一个物理来说有点波粒二象性,有波的特性也有粒子的特性。==语法层的的确确看到是别名和本体公用空间,但是底层你会发现他也是引用变量,那就是他有个双字四字节的小空间(和指针变量所占一样)==,我是这样理解的比如我们电脑系统不是装在硬盘里面的吗,我们开机是直接进入系统的,但实际上系统前面还有一点点的内存是存放系统信息的好像是ESP我也记不清了 ,那个东西要是没了,你系统就是废掉了,但是感觉举的例子不怎么恰当。我问过很多人,没有人说明白这个小悖论。。。烦啊。C++现在刚起步就要我头发
引用 语法层
引用概念
引用是也已存在的变量取一个别名,编译器不会为引用变量开辟内存空间(这是==语法层面==)它和它
引用的变量==共用同一块内存空间==
类型& 引用变量名(对象名) = 引用实体
==引用类型必须和引用实体是同种类型的==
引用特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体
引用做参数
传值
//传值
void Swap(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 0, b = 10;
cout << a << endl << b << endl << endl;
Swap(a, b);
cout << a << endl << b << endl << endl;
return 0;
}
传址
//传址
void Swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int a = 0, b = 10;
cout << a << endl << b << endl << endl;
Swap(&a, &b);
cout << a << endl << b << endl << endl;
return 0;
}
传引用
//传引用
void Swap(int& rx, int& ry)
{
int tmp = rx;
rx = ry;
rx = tmp;
}
int main()
{
int a = 0, b = 10;
cout << a << endl << b << endl << endl;
Swap(a, b);
cout << a << endl << b << endl << endl;
return 0;
}
传值、传引用效率比较
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低
#include<iostream>
using namespace std;
#include <time.h>
struct A
{
int a[10000];
};
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{
A a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
return 0;
}
引用做返回值
传值返回 所有的传值返回都会生成一个==拷贝==
临时变量存在哪
1.c比较小的(4字节 8字节),是==寄存器==充当临时变量
2.c比较大的,临时变量是放在上一层栈中的,比如这里的Add函数的栈帧
传引用返回
==错误用法==
==那么如何用呢==
注意:如果函数返回时,出了函数作用域,如果==返回对象还未还给系统==,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
值和引用的作为返回值类型的性能比较
#include<iostream>
using namespace std;
#include <time.h>
struct A
{
int a[10000];
};
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
void TestReturnByRefOrValue()
{
// 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{
TestReturnByRefOrValue();
return 0;
}
传值和指针在作为传参以及返回值类型上效率相差很大。
- 引用传参和返回值 有些场景下可以明显提高性能 ==大对象+深拷贝对象==
- 引用传参和返回值 输出型参数和输出型返回值 ==人话就是函数的形参改变可以改变函数外面的实参,有些场景下,引用返回,可以改变返回对象==
修改返回对象
用==引用==的返回==可读可写==
#define N 10
int& fun(const int& i)
{
static int a[N];
return a[i];
}
int main()
{
int i = 0;
for (i = 0; i < N; i++)
{
fun(i) = 100 + i;
}
for (i = 0; i < N; i++)
{
cout << fun(i) << " ";
}
return 0;
}
常引用
通过上面我们可以发现==const引用大小通吃==
==const type&== 可以接收各种类型的变量
这就引入了新的问题 ==const引用参数的好处==
左值右值
我们经常有一种误解,即在等号左边的叫做左值(L-value),右边的叫做右值(R-value)。这个说法其实是不准确的, 首先左值右值是针对表达式来说的。C++中左值被定义为Location Value,即==可以取地址的值==,或者说是指表达式结束后==仍然存在的值==。相反右值就是==临时的值==了
==不要想着越权,越权的人是我最讨厌的人==
我们假设x是个很大的对象或者是后面的深度拷贝的部分
那么我们就使用引用参数,这样是可以减少拷贝,来提高效率
假如x我们不需要改变它,我们就用const引用,来提高代码的安全性
引用 低层
我们通过vs19观察==别名==和==本体==的确是在同一个地址上,所以我们说了==语法上==别名是没有开辟空间的,但是实际上==底层实现==是有空间的,因为==引用是按照指针的方式来实现==的。
玩底层带你看汇编这是我最喜欢看的东西
linux下面正宗汇编看不懂
引用和指针的不同点:
- 引用在定义时==必须初始化==,指针没有要求
- 引用在初始化时引用一个实体后,就==不能再引用其他实体==,而指针可以在任何时候指向任何一个同类型实体
- ==没有NULL引用,但有NULL指针==
- ==在sizeof中含义不同==:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全
- 点赞
- 收藏
- 关注作者
评论(0)