自学内容网 自学内容网

引用

一、概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

二、特性

  • 引用类型必须和引用实体是同种类型
void TestRef()
{
  double a = 12.34;
  int &ra = a;  /* 错误:将类型为‘int&’的引用初始化为类型为‘double’的表达式无效 */
}
  • 引用在定义时必须初始化
void TestRef()
{
  int &ra;  /* 错误:‘ra’声明为引用却未被初始化 */
}
  • 引用一旦初始化引用一个实体后,再不能引用其他实体

  • 一个变量可以有多个引用

void TestRef()
{
  int a = 10;
  int &ra = a;
  int &rra = a;
   
  printf("%p %p %p\n", &a, &ra, &rra);  /* 输出结果一致 */
}

三、常引用

void TestConstRef()
{
  const int a = 10;
  /*
   * int &ra = a;
   * 错误:将类型为‘int&’的引用初始化为类型为‘const int’的表达式无效
   */
  const int &ra = a;
  printf("%p %p\n", &a, &ra);  /* 输出结果一致 */

  /*
   * int &b = 10;
   * 错误:用类型为‘int’的右值初始化类型为‘int&’的非常量引用无效
   */
  const int &b = 10;

  int c = 10;
  const int &rc = c;
  printf("%p %p\n", &c, &rc);  /* 输出结果一致 */

  double d = 12.34;
  const int &rd = d;
  printf("%p %p\n", &d, &rd);  /* 注意:输出结果不一致 */
}

四、使用场景

1、参数

void Swap(int &left, int &right)
{
  int temp = left;
  left = right
  right = temp;
}

2、返回值

#include <iostream>

using namespace std;

int &TestRef(int &r)
{
  r += 10;
  return r;
}

/*
 * 反面案例
 * 注意:如果函数返回时,离开函数作用域后,其栈上空间已经还给系统,因此不能用栈上的空间作为引用类型返回,
 * 如果以引用类型返回,返回值的生命周期必须不受函数的限制,即比函数生命周期长
 */
int &Add(int a, int b)
{
  int c = a + b;
  return c;
}

int main()
{
  int &r = Add(1, 2);
  Add(3, 4);
  count << "Add(1,2) is " << r << endl;
  return 0;
}

五、传值、传引性能比较

当参数或者返回值类型非常大时,用值作为参数或者返回值类型,性能是非常低下的,为什么?
传参需要参数压栈,返回值可参考C/C++函数返回值问题

那指针和引用作为参数和返回值类型的性能呢?

1、指针和引用作为参数类型的性能比较

#include <iostream>
#include <time.h>

using namespace std;

struct TestType
{
  int a[10000];
};

void TestFunc1(TestType *a)
{}

void TestFunc2(TestType &a)
{}

void TestRefAndPtr()
{
  TestType a;

  size_t begin1 = clock();
  for (size_t i = 0; i < 1000000; ++i)
    TestFunc1(&a);
  size_t end1 = clock();

  size_t begin2 = clock();
  for (size_t i = 0; i < 1000000; ++i)
    TestFunc2(a);
  size_t end2 = clock();

  cout << "TestFunc1(int *)-time: " << end1 - begin1 << endl;
  cout << "TestFunc1(int &)-time: " << end2 - begin2 << endl;
  cout << endl;
}

/* 多运行几次 */
int main()
{
  for (int i = 0; i < 10; i++)
    TestRefAndPtr();

  return 0;
}

2、指针和引用作为返回值类型的性能比较

#include <iostream>
#include <time.h>

using namespace std;

struct TestType
{
  int a[10000];
};

TestType a;

TestType *TestFunc1()
{
  return &a;
}

TestType &TestFunc2()
{
  return a;
}

void TestRefAndPtr()
{
  size_t begin1 = clock();
  for (size_t i = 0; i < 1000000; ++i)
    TestFunc1();
  size_t end1 = clock();

  size_t begin2 = clock();
  for (size_t i = 0; i < 1000000; ++i)
    TestFunc2();
  size_t end2 = clock();

  cout << "TestType *TestFunc1()-time: " << end1 - begin1 << endl;
  cout << "TestType &TestFunc1()-time: " << end2 - begin2 << endl;
  cout << endl;
}

/* 多运行几次 */
int main()
{
  for (int i = 0; i < 10; i++)
    TestRefAndPtr();

  return 0;
}

通过上述代码的比较,发现引用和指针在作为传参以及返回值类型上性能几乎相同

3、引用和指针的区别

在语法概念上,引用就是一个别名,没有独立空间,和其引用实体共用同一块空间,参考上述代码示例

在底层实现上实际是有空间的,因为引用是按照指针方式来实现的

/* 
 * 可以看下汇编代码
 * g++ -S -fverbose-asm -g test.cc -o test.s
 * as -alhnd test.s
 */
int main()
{
  int a = 10;

  int &ra = a;
  ra = 20;

  int *pa = &a;
  *pa = 20;

  return 0;
}

引用和指针的不同点:

  • 有 void *,没有 void &
  • 有 NULL 指针,没有 NULL 引用
  • 有多级指针,没有多级引用
  • 引用在定义时必须初始化,指针没有要求
  • 引用一旦初始化引用一个实体后,再不能引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  • 引用自加即引用的实体增加 1,指针自加即指针向后偏移一个类型的大小
#include <stdio.h>

int main()
{
  int a = 10;
  int &ra = a;
  int b = 20;
  int *pb = &b;

  printf("a: %d, ra: %d\n", a, ra);
  ra++;
  printf("ra: %d, a: %d\n", ra, a);


  printf("b: %d, pb: %llu\n", b, pb);
  (*pb)++;
  printf("pb: %llu, b: %d\n", pb, b);
  pb++;
  printf("pb: %llu, b: %d\n", pb, b);

  return 0;
}
  • sizeof 引用为引用类型的大小,sizeof 指针始终是地址空间所占字节数(32 位平台下占 4 字节,64 位平台下占 8 字节)
#include <stdio.h>

int main()
{
  int a;
  int &ra = a;
  int *pa = &a;

  printf("sizeof(ra): %d, sizeof(pa): %d\n"
    , sizeof(ra), sizeof(pa));  /* sizeof(ra): 4, sizeof(pa): 8 */

  return 0;
}
  • 引用比指针使用起来相对更安全

原文地址:https://blog.csdn.net/chirrupy_hamal/article/details/142703820

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!