Каталог статей
![Вставьте сюда описание изображения](https://img-blog.csdnimg.cn/ffb933014a074844be54e6ee0bc06abb.gif#pic_center)
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, указатель увеличивается, то есть указатель смещается назад на размер типа.
#Мои заметки по изучению языка программирования#