[Станция памяти C++] Цитата

Вставьте сюда описание изображения


Вставьте сюда описание изображения

1. Концепция котировки

Ссылка — это не вновь определенная переменная, а псевдоним существующей переменной. Компилятор не выделяет пространство памяти для ссылочной переменной. Она разделяет то же пространство памяти с переменной, на которую ссылается.

Как и в случае с игровыми персонажами League of Legends, в качестве примера возьмем героя Ван Хао.

             有些人叫他劲夫,有些人叫他腕豪,有些人叫他瑟提这三个名字说的都是他,只是不同人对他的叫法不同

Вставьте сюда описание изображения
Давайте использовать код в качестве примера:

int a = 0;
int b = a;

Вместо использования ссылок мы создаем две отдельные переменные и присваиваем значение a. Это создает два отдельных пространства памяти в памяти и сохраняет одно и то же значение, но с разными адресами.

Вставьте сюда описание изображения


int a = 0;
int& b = a;

Здесь мы сначала создаем переменную, открываем пространство памяти для хранения значения 0, а затем используем ссылку на переменную a и даем ей псевдоним b. Мы не будем открывать другое пространство с именем b. Адреса a и b одинаковы.
Вставьте сюда описание изображения
Мы можем убедиться в этом, напечатав адреса a и b:

cout << &a << endl;
cout << &b << endl;

результат:
Вставьте сюда описание изображения

Один и тот же адрес означает, что a и b представляют одно и то же пространство памяти. Что произойдет, если a++ и b++ будут находиться одновременно?

a++;
b++;

Результаты отладки таковы:
Вставьте сюда описание изображения
После a++ изменяется также b, а затем до b++ меняется также a, поэтому действие ++ выполняется одновременно для a и b, и a++ не будет, b остается неизменным, а операция b++, a не изменяется

2. Характеристики цитирования

1. Ссылки должны быть инициализированы после определения.

                                               意思是不能这样写

Пожалуйста, добавьте описание изображения

2. Переменная может иметь несколько ссылок

                          理论上可以给一个变量去无限个别名,甚至可以给这个变量的别名取别名

Пожалуйста, добавьте описание изображения
Для a++ отладьте его:

Пожалуйста, добавьте описание изображения

3. Если ссылка ссылается на объект, она не может ссылаться на другие объекты.

                                            引用很深情,它始终如一

Пожалуйста, добавьте описание изображения

                               外面的蝴蝶再多,只能让它的外表有所改变,但内心永远不变

3. Часто цитируемые

int main()
{
    
    
	//权限平移
	int a = 0;
	int& b = a;

	//权限放大 - 这是不允许的
	/*const int c = 0;
	int& d = c;*/

	//权限缩小
	int c = 0;
	const int& d = c;

	return 0;
}

权限平移: То есть a и b ранее не определены с помощью const. Оба они имеют одинаковые разрешения, оба доступны для чтения и записи
权限放大: это означает, что c был ограничен const только чтением и не доступен для записи, но его псевдоним d не имеет был ограничен. Ограничен только для чтения и не доступен для записи. Этот метод записи не поддерживается в синтаксисе C++.
权限缩小Он относится к ограничению псевдонима переменной только для чтения и запрета на запись, но сам по себе не ограничен только для чтения и не доступен для записи. записываемый.

Вставьте сюда описание изображения
Причина, по которой a типа int может быть присвоена типу b типа double, заключается в том, что пробел в середине создаст временную переменную и назначит ее b, а временная переменная имеет константность и произойдет неявное преобразование типа.
Вставьте сюда описание изображения
Почему псевдоним bb двойного типа a вызывает проблемы? Или это потому, 临时变量具有常性что это эквивалентно бытию const修饰, а bb не модифицируется константой, а передача временной переменной эквивалентна бытию 权限放大, поэтому будут проблемы.
Псевдониму bbb a предшествует модификация const, а затем он эквивалентен преобразованию разрешений с временной переменной, поэтому такой способ записи возможен.


4. Сценарии использования

1. Сделать параметры

1. Выходные параметры

В качестве примера возьмем функцию обмена Swap. Раньше для получения адреса переменной использовались два указателя, а затем соответствующие адреса разыменовывались для обмена. Теперь для реализации этой функции обмена можно использовать ссылки, что устраняет необходимость понять ссылку и процесс передачи адреса переменной, что делает общую информацию более краткой и эффективной.

void Swap(int& r1, int& r2)
{
    
    
	int tmp = r1;
	r1 = r2;
	r2 = tmp;
}

int main()
{
    
    
	int a = 1;
	int b = 2;
	Swap(a, b);
	return 0;
}

2. Передача параметров большого объекта

                                               作用:提高效率

a — это массив размером 40 000 байт, содержащийся в структуре A. Func1 напрямую передает целое a, а Func2 ссылается на a, которое по сути передавать не нужно. Следующий метод TestRefAndValue() записывает время, необходимое Func1 и Func2 для передачи параметров соответственно.

#include <time.h>
struct A{
    
     int a[10000]; };
void TestFunc1(A aa){
    
    }
void TestFunc2(A& aa){
    
    }
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;
}

Результат следующий:
Вставьте сюда описание изображения

Хотя разрыв может показаться не таким уж большим, если он накапливается много раз, он значительно увеличится.


2. Сделать возвращаемое значение

1. Возврат по значению

int Count()
{
    
    
	static int n = 0;
	n++;
	// ...
	return n;
}

int main()
{
    
    
	int ret = Count();
	return 0;
}
                                              Count的返回值就是n吗?
                                                   答案是否定的

Вставьте сюда описание изображения

                                        应该是n的一份拷贝tmp传递给main

因为在Count里面给n定义时加了static,所以n是放到内存中的静态去的,返回n时,是到静态区里面去找到n进行拷贝,再传拷贝值给ret
Вставьте сюда описание изображения
这里是传值返回,就算我们写代码时不加static定义n,在返回n之前,编译器也自动会进行对n进行拷贝,只是不会在静态区里面找,就直接在栈里面找就行


2. Возврат по ссылке

int& Count()
{
    
    
	int n = 0;
	n++;

	return n;
}

int main()
{
    
    
	int ret = Count();
	cout << ret << endl;
	cout << ret << endl;
	return 0;
}

Вставьте сюда описание изображения
int& 是引用返回的语法,含义是返回返回对象的别名
这里ret的结果是未定义的,如果返回结束时,系统会清理Count的栈置成随机值,那么这里的热ret就是随机值

в заключение: В приведенной выше программе по существу неправильно использовать возврат по ссылке, и результат не гарантирован.


int& Count()
{
    
    
	int n = 0;
	n++;

	return n;
}

int main()
{
    
    
	int& ret = Count();
	cout << ret << endl;
	cout << ret << endl;
	return 0;
}

Вставьте сюда описание изображения

в заключение: Когда область действия функции выходит за пределы области действия, возвращаемый объект уничтожается, поэтому вы не должны выполнять возврат по ссылке, вы должны возвращать значение по значению.


int& Count()
{
    
    
	static int n = 0;
	n++;

	return n;
}

int main()
{
    
    
	int& ret = Count();
	cout << ret << endl;
	cout << ret << endl;
	return 0;
}

                                            这样传引用返回就可以了

в заключение: Здесь n в Count сначала помещается в статическую область, чтобы оно не стало случайным значением при уничтожении кадра стека.


5. Сравнение эффективности передачи по значению и передачи по ссылке

Используйте значение в качестве параметра или типа возвращаемого значения. Во время передачи и возврата параметра функция не будет напрямую передавать фактический параметр или напрямую возвращать саму переменную. Вместо этого она будет передавать фактический параметр или возвращать временную копию переменной, поэтому используйте значение в качестве параметра. Или тип возвращаемого значения, эффективность очень низкая, особенно когда параметр или тип возвращаемого значения очень велики, эффективность еще ниже.


6. Разница между ссылками и указателями

                        在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间
int main()
{
    
    
	int a = 10;
	int& ra = a;
	cout << "&a = " << &a << endl;
	cout << "&ra = " << &ra << endl;
	return 0;
}

Тот же адрес
Вставьте сюда описание изображения

                            在底层实现上实际是有空间的,因为引用是按照指针方式来实现的
int main()
{
    
    
	int a = 10;
	int& ra = a;
	ra = 20;
	int* pa = &a;
	*pa = 20;
	return 0;
}

Вставьте сюда описание изображения
Откройте окно дизассемблирования, и вы увидите, что их основная логика на самом деле одинакова.

Разница между ссылками и указателями :

1. Ссылка концептуально определяет псевдоним переменной, а указатель хранит адрес переменной.
2. Ссылки должны быть инициализированы при их определении, и нет никаких требований к указателям.
3. После того, как ссылка ссылается на объект во время инициализации, она не может ссылаться на другие объекты, и указатель может указывать на любой
объект того же типа в любой момент. time
4. Нет NULL-ссылки, но есть NULL-указатель
5. Значение sizeof другое: результатом ссылки является размер ссылочного типа, но указатель всегда представляет собой количество байтов, занимаемых адресным пространством (
4 байта на 32-битной платформе)
6. Ссылка добавляется самостоятельно, то есть объект, на который ссылается, увеличивается на 1, указатель увеличивается, то есть указатель смещается назад на размер типа.

#Мои заметки по изучению языка программирования#Вставьте сюда описание изображения

Je suppose que tu aimes

Origine blog.csdn.net/cdtu_mid/article/details/132363086
conseillé
Classement