【C++ 記憶站】引用

在這里插入圖片描述

文章目錄

    • 一、引用概念
    • 二、引用特性
      • 1、引用在定義時必須初始化
      • 2、一個變量可以有多個引用
      • 3、引用一旦引用一個實體,再不能引用其他實體
    • 三、常引用
    • 四、使用場景
      • 1、做參數
        • 1、輸出型參數
        • 2、大對象傳參
      • 2、做返回值
        • 1、傳值返回
        • 2、傳引用返回
    • 五、傳值、傳引用效率比較
    • 六、引用和指針的區別

在這里插入圖片描述

一、引用概念

引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內存空間,它和它引用的變量共用同一塊內存空間

就比如英雄聯盟里面的游戲角色,就拿腕豪這個英雄來舉例吧

             有些人叫他勁夫,有些人叫他腕豪,有些人叫他瑟提這三個名字說的都是他,只是不同人對他的叫法不同

在這里插入圖片描述
再用代碼舉個例:

int a = 0;
int b = a;

這里沒有用引用,而是創建兩個單獨的變量,再把a的值賦給a,這在內存里創建了兩個單獨的內存空間且存儲的值相同,但是地址不同

在這里插入圖片描述


int a = 0;
int& b = a;

這里先是創建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 不變的情況

二、引用特性

1、引用在定義時必須初始化

                                               意思是不能這樣寫

請添加圖片描述

2、一個變量可以有多個引用

                          理論上可以給一個變量去無限個別名,甚至可以給這個變量的別名取別名

請添加圖片描述
對a++,在調試一下:

請添加圖片描述

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++語法里面是不支持的
權限縮小是指把一個變量的別名限定為只讀不可寫,自身不被限定為只讀不可寫

在這里插入圖片描述
int類型的a能賦值給double類型的b是因為中途空間會創建一個臨時變量賦值給b,而臨時變量具有常性,會發生一個隱性的類型轉換
在這里插入圖片描述
double類型的a的別名bb為什么會出現問題?還是因為臨時變量具有常性,相當于是被const修飾的而bb沒有被const修飾,臨時變量傳過去就相當于是權限放大,所以會有問題
a的別名bbb前面加上const修飾,之后就與臨時變量相當于是權限平移,所以這種寫法就可行


四、使用場景

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是一個大小為40000字節的數組,包含于結構體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;
}
                                            這樣傳引用返回就可以了

結論這里是先把Count里面的n放到靜態區,那么他就不會隨著棧幀的銷毀變成隨機值


五、傳值、傳引用效率比較

以值作為參數或者返回值類型,在傳參和返回期間,函數不會直接傳遞實參或者將變量本身直接返回,而是傳遞實參或者返回變量的一份臨時的拷貝,因此用值作為參數或者返回值類型,效率是非常低下的,尤其是當參數或者返回值類型非常大時,效率就更低


六、引用和指針的區別

                        在語法概念上引用就是一個別名,沒有獨立空間,和其引用實體共用同一塊空間
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. 引用在初始化時引用一個實體后,就不能再引用其他實體,而指針可以在任何時候指向任何
一個同類型實體
4. 沒有NULL引用,但有NULL指針
5. 在sizeof中含義不同:引用結果為引用類型的大小,但指針始終是地址空間所占字節個數(32
位平臺下占4個字節)
6. 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小

#我的編程語言學習筆記#在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/43250.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/43250.shtml
英文地址,請注明出處:http://en.pswp.cn/news/43250.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

label引用圖片出現??

參考latex 引用圖片“\ref figure”_latex \ref加上前綴fig_Junruiqwertyuiop的博客-CSDN博客 label需要放在caption后面&#xff0c;如 \caption{Overview of BERT.} \label{BERT} 猜測&#xff0c;label可能會根據圖表或者公式的caption與圖表或公式綁定并編號&#xff0…

【MT32F006】MT32F006之CS1237采集秤傳感器

本文最后修改時間&#xff1a;2023年06月07日 一、本節簡介 本文介紹如何使用MT32F006連接CS1237芯片采集秤傳感器。 二、實驗平臺 庫版本&#xff1a;V1.0.0 編譯軟件&#xff1a;MDK5.37 硬件平臺&#xff1a;MT32F006開發板&#xff08;主芯片MT32F006&#xff09; 仿真…

Chrome命令行開關

Electron 支持的命令行開關 –client-certificatepath 設置客戶端的證書文件 path . –ignore-connections-limitdomains 忽略用 , 分隔的 domains 列表的連接限制. –disable-http-cache 禁止請求 HTTP 時使用磁盤緩存. –remote-debugging-portport 在指定的 端口 通…

ORACLE中判斷表是否存在再刪除表避免報錯與MySql和SqlServer的不同

不同數據庫中drop a table if it exists的不同&#xff1a; In MySQL it is pretty easy to drop a table if it exists already. In Oracle and Microsoft’s SQL Server it is a little more complicated. Today I want to present you the solutions for these two DBMS’.…

常見的CRM系統報價

一個CRM系統大概多少錢&#xff1f;CRM系統的價格因為不同的廠商、功能、部署方式、用戶數等因素而有很大的差異&#xff0c;沒有一個固定的標準。但是&#xff0c;我們可以根據一些常見的CRM軟件的報價&#xff0c;對CRM價格有一個大致的了解。 一、CRM的部署方式 CRM系統的…

【RocketMQ】快速入門

文章目錄 消費模式同步消息異步消息單向消息延遲消息批量消息順序消息事務消息Tag標簽和Key鍵Tag的使用Key的使用 首先引入rocketmq的依賴 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client</artifactId><ve…

HackNos 3靶場

配置 進入控制面板配置網卡 第一步&#xff1a;啟動靶機時按下 shift 鍵&#xff0c; 進入以下界面 第二步&#xff1a;選擇第二個選項&#xff0c;然后按下 e 鍵&#xff0c;進入編輯界面 將這里的ro修改為rw single init/bin/bash&#xff0c;然后按ctrlx&#xff0c;進入…

數據結構的圖存儲結構

目錄 數據結構的圖存儲結構 圖存儲結構基本常識 弧頭和弧尾 入度和出度 (V1,V2) 和 的區別,v2> 集合 VR 的含義 路徑和回路 權和網的含義 圖存儲結構的分類 什么是連通圖&#xff0c;&#xff08;強&#xff09;連通圖詳解 強連通圖 什么是生成樹&#xff0c;生…

springboot集成ES

1.引入pom依賴2.application 配置3.JavaBean配置以及ES相關注解 3.1 Student實體類3.2 Teacher實體類3.3 Headmaster 實體類4. 啟動類配置5.elasticsearchRestTemplate 新增 5.1 createIndex && putMapping 創建索引及映射 5.1.1 Controller層5.1.2 service層5.1.3 ser…

leetcode做題筆記85最大矩形

給定一個僅包含 0 和 1 、大小為 rows x cols 的二維二進制矩陣&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面積。 示例 1&#xff1a; 思路一&#xff1a;單調棧 int maximalRectangle(char** matrix, int matrixSize, int* matrixColSize){int dp[matrixSize…

使用MAT分析OOM問題

OOM和內存泄漏在我們的工作中&#xff0c;算是相對比較容易出現的問題&#xff0c;一旦出現了這個問題&#xff0c;我們就需要對堆進行分析。 一般情況下&#xff0c;我們生產應用都會設置這樣的JVM參數&#xff0c;以便在出現OOM時&#xff0c;可以dump出堆內存文件&#xff…

基于libevent的tcp服務器

libevent使用教程_evutil_make_socket_nonblocking_易方達藍籌的博客-CSDN博客 一、準備 centos7下安裝libevent庫 yum install libevent yum install -y libevent-devel 二、代碼 server.cpp /** You need libevent2 to compile this piece of code Please see: http://li…

專訪 BlockPI:共建賬戶抽象未來的新一代 RPC 基礎設施

在傳統 RPC 服務板塊上&#xff0c;開發者一直飽受故障風險、運行環境混亂等難題的折磨。實現 RPC 服務的去中心化&#xff0c;且保持成本優勢和可擴展性&#xff0c;始終是區塊鏈基礎設施建設的重要命題之一。從 2018 年觀察中心化 RPC 供應商服務現狀開始&#xff0c;BlockPI…

內存管理(1)

內存管理&#xff08;1&#xff09; 1、各類型數據在內存中的存儲空間2、C內存管理方式2.1 針對于內置類型分析2.2 針對于自定義類型分析2.3 C語言與C在申請動態內存失敗時的區別 3、operator new 和 operator delete函數&#xff08;重點&#xff09;3.1 底層知識解析3.2 實現…

linux-shell腳本收集

創建同步腳本xsync mkdir -p /home/hadoop/bin && cd /home/hadoop/bin vim xsync#!/bin/bash#1. 判斷參數個數 if [ $# -lt 1 ] thenecho Not Arguementexit; fi#2. 遍歷集群所有機器 for host in node1 node2 node3 doecho $host #3. 遍歷所有目錄&#xff0c;挨…

web3:使用Docker-compose方式部署blockscout

最近做的項目,需要blockscout來部署一個區塊鏈瀏覽器,至于blockscout是什么,咱們稍后出一篇文章專門介紹下,本次就先介紹一下如何使用Docker-compose方式部署blockscout,以及過程中遇到的種種坑 目錄 先決條件我的環境準備工作Docker-compose1.安裝方式一:下載 Docker Co…

財務數據分析之現金流量表模板分享

現金流量表是我們常說的財務數據分析三表之一。它可以呈現一個企業的現金流情況&#xff0c;揭示企業經營管理健康狀態&#xff0c;但在實際使用中卻有總給人一種用不上、用不好的矛盾感。怎么才能把現金流量表做好&#xff1f;不如借鑒下大神的現金流量表模板。 下面介紹的是…

RabbitMQ-消息中間件學習記錄(what-how-why)

什么是消息中間件 簡單的來說就是消息隊列中間件&#xff0c;生產者發送消息到中間件&#xff0c;消息中間件用于 保存消息并發送消息到消費者。 消息中間件RabbitMQ的基本組件 1&#xff09;producer -生產者 2&#xff09;customer -消費者 3&#xff09;broker (經紀人)- M…

【Java 動態數據統計圖】動態數據統計思路案例(動態,排序,數組)四(116)

需求&#xff1a;&#xff1a;前端根據后端的返回數據&#xff1a;畫統計圖&#xff1b; 1.動態獲取地域數據以及數據中的平均值&#xff0c;按照平均值降序排序&#xff1b; 說明&#xff1a; X軸是動態的&#xff0c;有對應區域數據則展示&#xff1b; X軸 區域數據降序排序…

LabVIEW調用DLL傳遞結構體參數

LabVIEW 中調用動態庫接口時&#xff0c;如果是值傳遞的結構體&#xff0c;可以根據字段拆解為多個參數&#xff1b;如果參數為結構體指針&#xff0c;可用簇&#xff08;Cluster&#xff09;來匹配&#xff0c;其內存連續相當于單字節對齊。 1.值傳遞 接口定義&#xff1a; …