C++編程之旅-- -- --始探門庭的求知漫溯(二)

目錄

  • 引用
  • 內聯函數
  • (C++11)
    • auto關鍵字
    • 基于范圍的for循環
    • 指針空值---nullptr

引用

引用:指將變量以另一個名稱來展現的。它并非是一個新變量而是一個別名,它們同指一塊內存空間。就如古時那些有的人,亦或者是周樹人,你說魯迅是不是周樹人呢?在這里插入圖片描述

引用的形式:類型& 引用變量名(對象名) = 引用實體;
常引用: const 類型& 引用變量名(對象名) = 引用實體;
用常引用時要注意,他是常數的這個特性。

void TestRef()
{int a = 10;int& ra = a;//注意引用的類型要與引用的對象的類型一致!!!printf("%p\n", &a);printf("%p\n", &ra);
//常引用const int a = 10;//int& ra = a;   // 該語句編譯時會出錯,a為常量const int& ra = a;// int& b = 10; // 該語句編譯時會出錯,b為常量const int& b = 10;double d = 12.34;//int& rd = d; // 該語句編譯時會出錯,類型不同const int& rd = d;
}

引用的特點:
1.引用一定要初始化。
2.一個變量可以有多個引用。
3.一個引用不能指向多個變量。

引用的意義:
1.做參數。
2.做返回值。

對于引用做返回值有它的注意點:

#include<iostream>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;
}

你們認為結果是什么?其實是一個不可預測的值。
Add 函數里的 c 是局部變量,函數執行結束后,c 占用的內存會被釋放。返回 c 的引用(int&)后,main 里的 ret 會變成懸空引用(指向已釋放的內存 未定義行為)。后續調用 Add(3,4) 可能覆蓋這片內存, 把 ret 原本指向的無效內存數據改掉 ,導致 ret 輸出異常。
禁止返回局部變量的引用,否則會引發未定義行為;使用懸空引用 就是未定義行為 一切皆有可能。

做參數和返回值時 值與引用是有效率上的區別的:

#include<iostream>
#include <time.h>
using namespace std;
struct A { int a[10000]; };
void TestFunc1(A a) {
}
void TestFunc2(A& a)
{}
// 值返回
A TestFunc3(A a) { return a; }
// 引用返回
A& TestFunc4(A& a) { return a; }
int main()
{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;A b;A& B =b;// 以值作為函數的返回值類型size_t begin3 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc3(b);size_t end3 = clock();// 以引用作為函數的返回值類型size_t begin4 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc4(B);size_t end4 = clock();// 計算兩個函數運算完成之后的時間cout << "TestFunc3 time:" << end3 - begin3 << endl;cout << "TestFunc4 time:" << end4 - begin4 << endl;return 0;
}

在這里插入圖片描述

通過上述代碼的比較,發現傳值和指針在作為傳參以及返回值類型上效率相差很大。
傳值:簡單直接,但拷貝大型對象時效率低。
傳引用:避免拷貝,效率更高,適合傳遞大對象或需修改實參的場景。
實際開發中,優先用傳引用(或 const 引用) 處理復雜類型,減少不必要的性能損耗。

你們可能聽說引用其實就是指針,這是有一定來由的。

在語法概念上引用就是一個別名,沒有獨立空間,和其引用實體共用同一塊空間。
在底層實現上實際是有空間的,因為引用是按照指針方式來實現的。

引用和指針的不同點:

  1. 引用概念上定義一個變量的別名,指針存儲一個變量地址。
  2. 引用在定義時必須初始化,指針沒有要求。
  3. 引用在初始化時引用一個實體后,就不能再引用其他實體,而指針可以在任何時候指向任何
    一個同類型實體。
  4. 沒有NULL引用,但有NULL指針。
  5. 在sizeof中含義不同:引用結果為引用類型的大小,但指針始終是地址空間所占字節個數(32
    位平臺下占4個字節)。
  6. 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小。
  7. 有多級指針,但是沒有多級引用。
  8. 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理。
  9. 引用比指針使用起來相對更安全。

內聯函數

內聯函數:以inline修飾的函數叫做內聯函數(在函數的返回值類型前面加inline)編譯時C++編譯器會在調用內聯函數的地方展開(用函數體替換函數的調用),沒有函數調用建立棧幀的開銷,內聯函數提升程序運行的效率。

查看普通函數與內聯函數的區別方法:

  1. 在release模式下,查看編譯器生成的匯編代碼中是否存在call Add。
  2. 在debug模式下,需要對編譯器進行設置,否則不會展開(因為debug模式下,編譯器默認不
    會對代碼進行優化,以下給出vs2013的設置方式)
    debug模式下設置:
    開始:
    在這里插入圖片描述
    改變后:
    在這里插入圖片描述
    開始:
    在這里插入圖片描述

改變后:
在這里插入圖片描述
匯編代碼:
在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述
內聯函數:
特性本質:以空間換時間,編譯階段用函數體替換調用,減少調用開銷、提升效率,但可能使目標文件變大。

編譯器處理:inline 是給編譯器的建議,編譯器可選擇忽略,通常規模小、非遞歸、頻繁調用的函數建議用,遞歸等情況編譯器可能忽略該特性 。

適用與限制:用于優化規模小、流程直接、頻繁調用函數,多數編譯器不支持內聯遞歸函數,75 行這類較長函數也難在調用點內聯展開 。

inline 函數應該聲明和定義不分開。因為inline被展開,就沒有函數地址了,鏈接就會找不到。

inline函數其實還可以替代宏,那么我開始回憶宏的優缺點。
優點:
1.增強代碼的復用性。
2.提高性能。
缺點:
1.不方便調試宏。(因為預編譯階段進行了替換)
2.導致代碼可讀性差,可維護性差,容易誤用。
3.沒有類型安全的檢查 。
而我們可以在C++用這兩種方法來代替宏。

  1. 常量定義 換用const enum
  2. 短小函數定義 換用內聯函數

(C++11)

auto關鍵字

在我們做的程序變得越來越大,我們所用的類型名稱也會變得越來越難寫(復雜)和含義不明確導致容易出錯。對此我們之前可以用typedef來縮短名稱,然而typedef 讓類型別名和 const 的組合語義變得不直觀,容易坑人。

typedef char* pstring;
int main()
{const pstring p1;    // 編譯成功還是失敗?const pstring* p2;   // 編譯成功還是失敗?return 0;
}

在早期C/C++中auto的含義是:使用auto修飾的變量,是具有自動存儲器的局部變量,但遺憾的
是一直沒有人去使用它,因為局部變量默認就是自動存儲類型,使用 auto 修飾屬于多余操作, 其修飾效果和不修飾一樣,因此無人使用。

C++11中,標準委員會賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一
個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導而得。

在編譯階段編譯器需要根據初始化表達式來推導auto的實際類型。因此auto并非是一種類型的聲明,而是一個類型聲明時的占位符,編譯器在編譯期會將auto替換為變量實際的類型。因此使用auto定義變量時必須對其進行初始化。

auto 使用的細則:
1.auto 與指針和引用的注意事項:auto對于指針可以用auto或auto*,auto對于引用必須要加&:auto&。
2.auto對于同一行有多個變量的定義,他會先通過識別第一個變量類型,再用第一個變量類型賦給接下來的變量。因此要多個變量的類型一致。
3.auto不能用的場景:做函數參數,不能用在數組。
4. 為了避免與C++98中的auto發生混淆,C++11只保留了auto作為類型指示符的用法
5. auto在實際中最常見的優勢用法就是跟C++11提供的新式for循環,還有lambda表達式等進行配合使用。

基于范圍的for循環

這個改動是為了對于一個有范圍的集合而言,由程序員來說明循環的范圍是多余的,有時候還會容易犯錯誤。因此C++11中引入了基于范圍的for循環。for循環后的括號由冒號“ :”分為兩部分:第一部分是范圍內用于迭代的變量,第二部分則表示被迭代的范圍。

void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)//第一部分:auto& e,第二部分:arraye *= 2;
for(auto e : array)cout << e << " ";
return 0;
}

與普通循環類似,可以用continue來結束本次循環,也可以用break來跳出整個循環。

基于范圍的for循環使用條件:
1.因為是基于范圍的,所以對于遍歷的對象都要知其范圍。
2.迭代的對象要實現++和==的操作

指針空值—nullptr

在C++98中的指針空值:NULL,NULL實際是一個宏,NULL可能被定義為字面常量0,或者被定義為無類型指針(void*)的常量。
那么就會出現問題:

void f(int)
{cout<<"f(int)"<<endl;
}
void f(int*)
{cout<<"f(int*)"<<endl;
}
int main()
{f(0);f(NULL);f((int*)NULL);return 0;
}

這里是想通過f(NULL)調用指針版本的f(int*)函數,但是由于NULL被定義成0,因此與程序的
初衷相悖。
在C++98中,字面常量0既可以是一個整形數字,也可以是無類型的指針(void*)常量,但是編譯器
默認情況下將其看成是一個整形常量,如果要將其按照指針方式來使用,必須對其進行強轉(void
*)0。

對于nullptr有下面的注意:

  1. 在使用nullptr表示指針空值時,不需要包含頭文件,因為nullptr是C++11作為新關鍵字引入
    的。
  2. 在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節數相同。
  3. 為了提高代碼的健壯性,在后續表示指針空值時建議最好使用nullptr。

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

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

相關文章

wordpress網站的“管理員郵箱地址”有什么用?

在WordPress網站的“設置”-“常規”中設置的“管理員郵箱地址”有多種用途&#xff0c;以下是詳細介紹&#xff1a; 一、用戶注冊相關 密碼找回功能 當網站用戶忘記密碼時&#xff0c;他們會通過點擊登錄頁面上的“忘記密碼”鏈接來重置密碼。WordPress系統會向管理員郵箱地…

202506 電子學會青少年等級考試機器人六級實際操作真題

更多內容和歷年真題請查看網站&#xff1a;【試卷中心 -----> 電子學會 ----> 機器人技術 ----> 六級】 網站鏈接 青少年軟件編程歷年真題模擬題實時更新 202506 青少年等級考試機器人實操真題六級 一、實際操作 1. 主題&#xff1a;姿態傳感器交互步進電機左右…

Centos 安裝 redis

1.下載redis&#xff0c;這個自己去網上找吧。2.上傳文件&#xff0c;redis-7.4.1.tar.gz3.解壓&#xff1a;執行 tar -xf redis-7.4.1.tar.gz在進行安裝之前&#xff0c;檢查一下有沒有make、gcc、python3、沒有的話全部 yum install。安裝完之后&#xff0c;如果報一下錯誤&a…

算法訓練營DAY55 第十一章:圖論part05

并查集理論基礎 背景 當我們需要判斷兩個元素是否在同一個集合里的時候&#xff0c;我們就要想到用并查集。 并查集主要有兩個功能&#xff1a; 將兩個元素添加到一個集合中。判斷兩個元素在不在同一個集合 原理講解 從代碼層面&#xff0c;我們如何將兩個元素添加到同一個…

docker相關操作記錄

1.docker清理服務器上面沒有用到的鏡像#刪除本地鏡像 docker rmi $(docker images -q) #強制刪除本地鏡像 docker rmi $(docker images -q) -f2.docker查看日志docker logs c36c56e4cfa3 (容器id)3.所有運行或沒有運行的鏡像 docker ps -a4、停止container&#xff0c;這樣才…

LInux基礎學習筆記七

/dev/zero和/dev/null 是什么/dev/zero&#xff1a;一個零設備文件&#xff0c;讀取時會不斷返回\0字節&#xff08;零值字節&#xff09;&#xff0c;常用于創建空文件或格式化/dev/null&#xff1a;一個空設備文件&#xff0c;寫入它的內容會被丟棄&#xff0c;相當于“黑洞”…

軟件架構:系統結構的頂層設計與戰略約束

軟件架構&#xff1a;系統結構的頂層設計與戰略約束軟件架構是軟件系統的“骨架”與“憲法”&#xff0c;它定義了系統的根本性組織結構&#xff0c;包括構成系統的關鍵構件、它們之間的組織關系、交互機制、約束原則以及指導性決策。它決定了系統在性能、可擴展性、可靠性、可…

基于spring boot的個人博客系統

2 開發技術 3 2.1 VUE框架 3 2.2 Mysql數據庫 3 2.3 Spring Boot框架 3 2.4 layui介紹 4 本程序在設計結構選擇上首選B/S&#xff0c;也是為了滿足程序今后升級便利&#xff0c;以及程序低維護成本的要求。本程序的網絡拓撲設計也會在下圖展示&#xff0c;通過圖形的方式來描述…

Excel制作尖刀圖,直觀展示業績漲跌

Excel制作尖刀圖&#xff0c;直觀展示業績漲跌效果展示下圖是一個常見的兩年業績同比表&#xff0c;也是尖刀圖很常見的數據源類型&#xff0c;但是這個數據格式是無法直接制作的&#xff0c;需要對數據進行加工。1.對數據進行逆透視使用excel進行逆透視&#xff0c;最常見的方…

兩種路由模式(React-Router 8)

倆種路由模式 各個主流框架的路由常用的路由模式有倆種&#xff0c;history模式和hash模式,ReactRouter分別由createBrowerRouter和createHashRouter函數負責創建附帶代碼:import Login from "../page/Login"; import Article from "../page/Article"; imp…

【01】OpenCV C++實戰篇——基于多項式插值的亞像素邊緣定位算法

文章目錄一. 背景二. 你的經歷三. 代碼實現(龜速版——單線程)3.1 梯度幅值3.1.1 生成 8 個方向模板3.1.2 計算梯度3.1.3 顯示梯度圖像3.1.4 程序運行演示3.2 梯度方向 &#xff08;梯度最大幅度值和方向&#xff09;3.3 單像素邊緣3.4 梯度單像素邊緣提取 運行測試四 、亞像素…

400V降24V,200mA,應用領域:從生活到工業的 “全能電源管家”WD5208

WD5208 電源芯片&#xff1a;小身材蘊藏大能量的電源控制新星在電源芯片的技術星河中&#xff0c;WD5208 憑借獨特性能與廣泛適用性嶄露頭角&#xff0c;成為眾多電子設備電源方案的優選。本文將全面解析這款芯片的核心優勢、應用場景與技術細節&#xff0c;展現其 “小身材&am…

C++ 引用 和 指針 的區別

特性引用指針初始化不能為 null&#xff0c;必須綁定到有效的對象可以為 null&#xff0c;不指向任何對象重新綁定不能重新綁定&#xff0c;一旦初始化后始終引用同一個對象可以重新指向其他對象內存占用不占用額外內存&#xff0c;編譯器通常將其優化為所引用的對象占用額外內…

Claude Code實戰體驗:AI智能編程助手如何重塑開發工作流?

一、背景介紹 AI大模型的爆發&#xff0c;讓各種智能編碼工具如雨后春筍般涌現。Claude Code就是其中非常有代表性的一款——它不僅能補全代碼、查找Bug&#xff0c;還能理解復雜需求&#xff0c;甚至幫你寫文檔、生成測試用例。作為一名全棧開發者&#xff0c;我和團隊最近幾個…

centos7 個人網站搭建之gitlab私有化部署實現線上發布

文章目錄 效果展示架構設計申請免費阿里云服務器嘗試連接遠程服務 開放端口申請域名 綁定云服務器組網網關服務器配置轉發代理網關服務器配置ssl 證書問題排查證書申請時報錯&#xff1a;Set the \server_name\ directive ti use the Nginx installer. gitlab私有化部署搭建git…

小米4A千兆版路由器刷機,解決Telnet無法連接問題

刷機極容易變磚&#xff0c;建議完全理清步驟后再進行操作 工具準備 1、小米4A千兆版路由器&#xff08;注意一定是千兆版&#xff0c;只是4A無千兆按下列步驟會變磚&#xff09;&#xff0c;適配電源線 2、網線一根 3、需保證刷機過程中網線接入是有網的&#xff0c;無需賬號認…

計算機網絡:如何將一個B類IP地址分為4個子網

要將一個B類IP地址劃分為4個子網&#xff0c;需通過子網掩碼擴展&#xff08;即借位&#xff09;來實現。以下是詳細步驟和原理&#xff1a; 一、B類IP地址的基礎特性 默認網絡位&#xff1a;B類地址前16位為網絡位&#xff08;標識網絡&#xff09;&#xff0c;后16位為主機位…

K8S 性能瓶頸排查

K8S 性能瓶頸排查 隨著業務量增長,Kubernetes 集群經常出現: ? Pod 啟動慢? ? API 響應慢? ? 節點 CPU 飆高? ? 服務無故中斷? 這可能是性能瓶頸在悄悄作祟。 性能瓶頸全局視角 # K8S 性能瓶頸排查思維導圖- 集群層面- API Server 響應慢- Etcd 壓力大- 控制面組件…

實習005 (web后端springboot)

五種創建方式一、方法一&#xff08;直接創建&#xff09;二、方法二&#xff08;阿里云&#xff09;三、方法三&#xff08;從官網&#xff09;或者說四、方法四、&#xff08;案例云官網&#xff09;五、方法五、&#xff08;自己寫&#xff09;先構建javaweb項目刷新后還是出…

基于vscode連接服務器實現遠程開發

目錄 一、背景介紹 1.1 什么是遠程開發 1.2 版本清單 二、以Java項目開發為例 2.1 安裝遠程開發插件 2.2 安裝語言開發插件 2.3 新建ssh連接 2.4 打開服務器目錄 一、背景介紹 1.1 什么是遠程開發 遠程開發是基于服務器環境進行實現本地開發操作&#xff0c;…