Reference -- C + + basic knowledge points

Posted by Risingstar on Fri, 08 Oct 2021 04:02:23 +0200

extern "c"



quote

Instead of defining a new variable, a reference gives an alias to an existing variable. The compiler will not open up memory space for the referenced variable. It shares the same memory space with the variable it references.

#include <iostream>
using namespace std;  // C + + standard library
int main()
{
	int a = 10;
	int& b = a;
	return 0;
}


Changes in formal parameter variables affect arguments - pointers or references

#include <iostream>
using namespace std;  // C + + standard library
int main()
{
	int a = 10;
	int& b = a;
	int& c = a;
	int& d = b;
	c = 20;
	d = 30;
	return 0;
}



Previous exchange writing

#include <iostream>
using namespace std;  // C + + standard library

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
int main()
{
    int x = 0, y = 1;
	Swap(&x, &y);
}

Now – use the reference

void Swap(int& rx, int& ry)
{
	int tmp = rx;
	rx = ry;
	ry = tmp;
}
int main()
{
	int x = 0, y = 1;
	Swap(x, y);
}


Write before stack initialization

typedef struct Stack
{
	int* a;
	int top;
	int capacity;
}ST;
void StackInit(ST* ps)
{
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}
int main()
{
	ST st;
	StackInit(&st);
	return 0;
}

Stack initialization – use post reference writing

typedef struct Stack
{
	int* a;
	int top;
	int capacity;
}ST;
void StackInit(ST& rs)
{
	rs.a = NULL;
	rs.top = rs.capacity = 0;
}
int main()
{
	int x = 0, y = 1;
	Swap(&x, &y);
	Swap(x, y);

	ST st;
	StackInit(st);
	
	SListNode* plist = NULL;
	SListPushBack(plist, 1);
	SListPushBack(plist, 2);
	return 0;
}


Use of references in single linked lists

typedef struct SListNode
{
	struct SListNode* next;
	int val;
}SLTNode, *PSLTNode;

//Void slistpushback (PSLTNode & phead, int x) -- this is not recommended. PSLTNode is a pointer to the structure diagram
void SListPushBack(SLTNode*& phead, int x)
{
	SLTNode* newnode;
	if (phead == NULL)
	{
		phead = newnode;
	}
	else
	{
     //...
	}
}
int main()
{
	SListNode* plist = NULL;
	SListPushBack(plist, 1);
	SListPushBack(plist, 2);
	return 0;
}

Alias pointer variable

int main()
{
	int x = 0, y = 1;
	int* p1 = &x;
	int* p2 = &y;

	int*& p3 = p1;  // Alias pointer variable
	*p3 = 10;
	 p3 = p2;
}

const and reference

  • The condition that I become your alias: your read-write permission can be unchanged or reduced, but your read-write permission can't be enlarged
int main()
{
	const int a = 10;
	 int& b = a;  // Become your alias and modify you (no)

	int c = 20;
	const int& d = c; // Become your alias without modifying you (line)
}
  • Aliases can be changed, but not all aliases have the same permissions as the original name (d only aliases, but cannot be modified)

Process of reference conversion

int main()
{
	int i = 10;
	double d = i;
	const double& r = i;

	char ch = 0xff;
	int j = 0xff;
	int k = ch;
	// ch will be promoted and converted into int type, and then compared with the position symbol bit during promotion
	// Here we raise ch, do you turn ch into an int?, Is to generate a temporary variable int
	if (ch == j) 
	{
		cout << "identical" << endl;
	}
	else
	{
		cout << "inequality" << endl;
	}
	return 0;
}

Benefits of const

typedef struct Stack
{
	int a[1000];
	int top;
	int capacity;
}ST;
void StackInit(ST& s) // The purpose of passing references here is to change formal parameters and affect arguments
{
	s.top = 0;
	s.capacity = 1000;
	// ...
}
void PrintStack(const ST& s)  
// 1. Reference passing is to reduce the copy of value passing and parameter passing  
// 2. You can protect parameters from being changed
{
	// Suppose there is such a logic - > If const is referenced at time, it can be checked here
	//if (s.capacity = 0) / / it should have been = =, which was written carelessly=
	{
	}
}
void func(const int& n) // The second advantage of const as a parameter is that it can receive variables or constants
{
}
int main()
{
	ST st;
	StackInit(st);
	// ...
	PrintStack(st);
	int i = 10;
	const int j = 30;
	func(i);
	func(20);
	func(j);
	return 0;
}
  • Benefit 1

void PrintStack(const ST& s)
Add reference – void printstack (const st & S) does not need a pointer, but uses references to reduce the copy when passing values and parameters

Add const – it can protect the formal parameters from being changed. In case it is written as if(s.capacity=0) {}, the formal parameters will be changed

  • Benefit 2
    The second advantage of const as a parameter is that it can receive variables or constants

  • summary
    If you want to reduce the copy of function parameters, you use reference parameters. If you don't change this parameter in the function, you'd better use const reference parameters

Reference as return value

Value transfer return

int Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	 int ret = Add(1, 2);
	Add(3, 4);
	cout << "Add(1, 2) is :" << ret << endl;
	return 0;
}

Value transfer return

int Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	 const int& ret = Add(1, 2);//Temporary variables are constant, so you need to add const
	Add(3, 4);
	cout << "Add(1, 2) is :" << ret << endl;
	return 0;
}


Reference return

  • If the alias is returned without a return value, it may lead to cross-border access and uncertain results, because the stack frame is destroyed, and the value of – C is random
  • Stack frames are not cleared on vs, and the result is 3
int& Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int& ret = Add(1, 2);//ret is the alias of c
	//Add(3, 4);
	printf("hello world\n");
	cout << "Add(1, 2) is :" << ret << endl;
	return 0;
}
  • Add another layer of reference to ret – vs. there is also an error
int& Add(int a, int b)
{
	int c = a + b;
	return c;
}

int main()
{
	int& ret = Add(1, 2);
	//Add(3, 4);
	printf("hello world\n");
	cout << "Add(1, 2) is :" << ret << endl;
	return 0;
}


Summary: when to use references

Test reference
It can't be measured once

#include <time.h>
struct A
{
	int a[10000];
};
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{
	A a;
	// Take value as function parameter
	size_t begin1 = clock();
		TestFunc1(a);
	size_t end1 = clock();
	// Take reference as function parameter
	size_t begin2 = clock();
		TestFunc2(a);
	size_t end2 = clock();
	// Calculate the time after the two functions run respectively
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

The cpu is too fast

Repeat 10000 times, transfer 10000 bytes and reference 10000 times

#include <time.h>
struct A
{
	int a[10000];
};
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{
	A a;
	// Take value as function parameter
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc1(a);
	size_t end1 = clock();
	// Take reference as function parameter
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc2(a);
	size_t end2 = clock();
	// Calculate the time after the two functions run respectively
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

References and pointers

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

	int* pa = &a;
	*pa = 30;
	return 0;
}
  • Understanding is OK

Topics: C++