C++之旅-C++11的深度剖析(1)

目錄

前言/背景

1.C++11的發展歷史

?2.列表初始化

2.1 C++98傳統的{}

2.2 C++11中的{}

2.3 C++11中的std::initializer_list

3.右值引用

3.1 左值和右值

3.2 左值引用和右值引用

3.3 引用延長生命周期

3.4 左值和右值的參數匹配

結束語


前言/背景

隨著現代軟件開發的快速發展,編程語言也在不斷進化,C++ 作為一種功能強大的編程語言,已經經歷了多個版本的更新,每一次版本的發布都為開發者帶來了新的特性和功能。C++11 是 C++ 語言的一個重要版本,它于 2011 年正式發布,并引入了許多全新的特性,極大地提升了代碼的效率、可讀性以及程序的執行性能。

C++11 的發布不僅對 C++ 開發者來說是一次重大提升,它還為整個編程社區提供了更加現代化的編程工具。從增強的類型推斷到智能指針,從并發編程的支持到對Lambda表達式的引入,C++11 使得開發者在編寫高效且可維護的代碼時擁有了更多的選擇。

然而,C++11 的變化不僅僅體現在語法層面,它還在性能優化和多線程編程上做出了許多貢獻,這使得 C++ 成為更加強大和靈活的語言,尤其適用于復雜的系統級應用、圖形處理和高性能計算等領域。

在這篇博客中,我們將深入探討 C++11 的一些核心特性,并通過實際示例幫助大家理解它們的應用場景和優勢。如果你是 C++ 的開發者,或者對 C++11 的新特性感興趣,那么這篇博客將幫助你更好地掌握這個版本的精髓,并將其應用到實際開發中去。?

1.C++11的發展歷史

C++11 是 C++ 的第二個主要版本,并且是從 C++98 起的最重要更新。它引入了大量更改,標準化了既有實踐,并改進了對 C++ 程序員可用的抽象。在它最終由 ISO 在 2011 年 8 月?12 日采納前,人們曾使用名稱“C++0x”,因為它曾被期待在 2010 年之前發布。C++03 與 C++11 期間花了 8 年時間,故而這是迄今為止最長的版本間隔。從那時起,C++ 有規律地每 3 年更新一次。

?2.列表初始化

2.1 C++98傳統的{}

C++98中一般數組和結構體可以用{}進行初始化。
struct Point
{
int _x;
int _y;
};
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
return 0;
}

2.2 C++11中的{}

? C++11以后想統一初始化方式,試圖實現一切對象皆可用{}初始化,{}初始化也叫做列表初始化。
? 內置類型支持,自定義類型也支持,自定義類型本質是類型轉換,中間會產生臨時對象,最后優化了以后變成直接構造。
? {}初始化的過程中,可以省略掉=
? C++11列表初始化的本意是想實現一個大統一的初始化方式,其次在有些場景下帶來的不少便利,如容器push/inset多參數構造的對象時,{}初始化會很方便

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
struct P{int a;int b;
};
class Date {
public:Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;}Date(const Date& d):_year(d._year) , _month(d._month), _day(d._day){cout<<"Date(const Date& d)"<<endl;}private:int _year;int _month;int _day;
};
int main() {
//	//C++98支持int a[]={1,2,3,4,5};int a2[5] = { 0 };P p = { 1, 2 };
//	// C++11?持的
//  // 內置類型?持int x1 = { 2 };
//	// ?定義類型?持這?本質是?{ 2025, 1, 1}構造?個Date臨時對象臨時對象再去拷?構造d1,編譯器優化后合?為?變成{ 2025, 1, 1}直接構造初始化
//
//	// 運??下,我們可以驗證上?的理論,發現是沒調?拷?構造的Date d1 = { 2025, 1, 1 };
//	// 這?d2引?的是{ 2024, 7, 25 }構造的臨時對象const Date& d2 = { 2024, 7, 25 };
//	// 需要注意的是C++98?持單參數時類型轉換,也可以不?{}Date d3 = { 2025 };Date d4 = 2025;
//	// 可以省略掉=P p1{ 1, 2 };int x2{ 2 };Date d6{ 2024, 7, 25 };const Date& d7{ 2024, 7, 25 };不?持,只有{}初始化,才能省略=vector<Date> v;v.push_back(d1);v.push_back(Date(2025, 1, 1));// ?起有名對象和匿名對象傳參,這?{}更有性價?v.push_back({ 2025, 1, 1 });return 0;
}

2.3 C++11中的std::initializer_list

上面的初始化已經很方便,但是對象容器初始化還是不太方便,比如一個vector對象,我想用N個值去構造初始化,那么我們得實現很多個構造函數才能支持, vector<int> v1 =
{1,2,3};vector<int> v2 = {1,2,3,4,5};
? C++11庫中提出了一個std::initializer_list的類, auto il = { 10, 20, 30 }; // the
type of il is an initializer_list ,這個類的本質是底層開一個數組,將數據拷貝過來,std::initializer_list內部有兩個指針分別指向數組的開始和結束。
? 容器支持一個std::initializer_list的構造函數,也就支持任意多個值構成的 {x1,x2,x3...} 進行
初始化。STL中的容器支持任意多個值構成的 {x1,x2,x3...} 進行初始化,就是通過
std::initializer_list的構造函數支持的。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<string>
#include<map>
using namespace std;
int main()
{std::initializer_list<int> mylist;mylist = { 10, 20, 30 };cout << sizeof(mylist) << endl;// 這?begin和end返回的值initializer_list對象中存的兩個指針// 這兩個指針的值跟i的地址跟接近,說明數組存在棧上int i = 0;cout << mylist.begin() << endl;cout << mylist.end() << endl;cout << &i << endl;// {}列表中可以有任意多個值// 這兩個寫法語義上還是有差別的,第?個v1是直接構造,// 第?個v2是構造臨時對象+臨時對象拷?v2+優化為直接構造vector<int> v1({ 1,2,3,4,5 });vector<int> v2 = { 1,2,3,4,5 };const vector<int>& v3 = { 1,2,3,4,5 };// 這?是pair對象的{}初始化和map的initializer_list構造結合到?起?了map<string, string> dict = { {"sort", "排序"}, {"string", "字符串"} };// initializer_list版本的賦值?持v1 = { 10,20,30,40,50 };return 0;
}

3.右值引用

3.1 左值和右值

? 左值是一個表示數據的表達式(如變量名或解引用的指針),一般是有持久狀態,存儲在內存中,我們可以獲取它的地址 ,左值可以出現賦值符號的左邊,也可以出現在賦值符號右邊。定義時const 修飾符后的左值,不能給他賦值,但是可以取它的地址。
int main() {int* p = new int(0);*p = 10;int c = 1;const int b = c;string s = "hello";string s1("world");/*cout << *p << endl;*/cout << &p << endl;cout << &b << endl;cout << &s << endl;cout << &s1 << endl;cout << (void*) & s1[0] << endl;return 0;
}

?

右值也是一個表示數據的表達式,要么是字面值常量、要么是表達式求值過程中創建的臨時對象
右值可以出現在賦值符號的右邊,但是不能出現出現在賦值符號的左邊, 右值不能取地址。

// 右值:不能取地址
double x = 1.1, y = 2.2;
// 以下?個10、x + y、fmin(x, y)、string("11111")都是常?的右值
10;
x + y;
fmin(x, y);
string("11111");
cout << &10 << endl;
cout << &(x+y) << endl;
cout << &(fmin(x, y)) << endl;
cout << &string("11111") << endl;

值得一提的是,左值的英文簡寫為lvalue,右值的英文簡寫為rvalue。傳統認為它們分別是left
value、right value 的縮寫。現代C++中,lvalue 被解釋為loactor value的縮寫,可意為存儲在內
存中、有明確存儲地址可以取地址的對象,而?rvalue 被解釋為 read value,指的是那些可以提供數據值,但是不可以尋址,例如:臨時變量,字面量常量,存儲于寄存器中的變量等, 也就是說左 值和右值的核心區別就是能否取地址。

3.2 左值引用和右值引用

1.Type& r1 = x; Type&& rr1 = y; 第一個語句就是左值引用,左值引用就是給左值取別
名,第二個就是右值引用,同樣的道理,右值引用就是給右值取別名。
int main() {// 左值:可以取地址
// 以下的p、b、c、*p、s、s[0]就是常?的左值int* p = new int(0);int b = 1;const int c = b;*p = 10;string s("111111");s[0] = 'x';double x = 1.1, y = 2.2;//左值引用給左值取別名int& r1 = b;int *&r2 = p;int &r3 = *p;string& r4 = s;char &r5 = s[0];return 0;}

?右值引用給右值取別名

int && rr1= 10;
int && rr2 = x + y;
double && rr3 = fmin(x, y);
string && rr4 = string("11111");
2.左值引用不能直接引用右值,但是const左值引用可以引用右值
//const左值引用可以引用右值
const int& rr5 = 10;
const int& rr6 = x + y;
const double& rr7 = fmin(x, y);
const string& rr8 = string("11111");
3.右值引用不能直接引用左值,但是右值引用可以引用move(左值)
//右值引用move左值
int&&rrx1= move(b);
int*&&rrx2= move(p);
int&&rrx3= move(*p);
string&&rrx4= move(s);
char&&rrx5= move(s[0]);

4.template <class T> typename remove_reference<T>::type&& move (T&&
arg); ?move是庫里面的一個函數模板,本質內部是進行強制類型轉換,當然他還涉及一些引總折疊的知識,這個后面會細講。
5.?需要注意的是變量表達式都是左值屬性,也就意味著一個右值被右值引用綁定后,右值引用變量變量表達式的屬性是左值

// b、r1、rr1都是變量表達式,都是左值
cout<<&b<<endl;
cout<<&r1<<endl;
cout << &rr1 << endl;
// 這?要注意的是,rr1的屬性是左值,所以不能再被右值引?綁定,除?move?下
int& r6 = r1;
//int&& rrx6 = rr1;--報錯
int&& rrx6 = move(rr1);

3.3 引用延長生命周期

右值引用可用于為臨時對象延長生命周期,const 的左值引用也能延長臨時對象生存期,但這些對象無法被修改。
int main() {string s1="hello";//string&& s2 = s1;//不能右值引用綁定左值const string& s2 = s1 + s1;// OK:到 const 的左值引?延??存期// r2 += "Test"; // 錯誤:不能通過到 const 的引?修改string&& r3 = s1 + s1; // OK:右值引?延??存期r3 += "Test"; // OK:能通過到? const 的引?修改cout << r3 << '\n';return 0;
}

3.4 左值和右值的參數匹配

1.C++98中,實現一個const左值引用作為參數的函數,那么實參傳遞左值和右值都可以匹配。
2.?C++11以后,分別重載左值引用、const左值引用、右值引用作為形參的f函數,那么實參是左值會匹配f(左值引用),實參是const左值會匹配f(const 左值引用),實參是右值會匹配f(右值引用)。
注意
右值引用變量在用于表達式時屬性是左值,這個設計這里會感覺跟怪,下一博客講右值引用的使用場景時,就能體會這樣設計的價值了

void fun1(int& x) {cout<< "左值引用重載func1(int&x)" << endl;
}
void fun1(int&& x) {cout << "右值引用重載func1(int&&x)" << endl;
}
void fun1(const int& x) {cout << "左值引用重載func2(const int&x)" << endl;
}
int main() {int x = 10;const int y = x;fun1(x);fun1(10);  // 如果沒有 fun1(int&&) 重載則會調? fun1(const int&)fun1(y);// 右值引?變量在?于表達式時是左值int&& r = 10;fun1(r);fun1(move(r));return 0;
}

結束語

本節內容就到此結束了,C++11的知識還有很多,下篇博客我們將詳細講解右值引用和移動語義的應用!!!?

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

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

相關文章

什么是手機9008模式?如何進入9008

之前給大家分享了一些有關手機刷機的知識&#xff0c;今天給大家講一講如果刷機過程中不慎變磚應該如何應對&#xff08;當然了&#xff0c;希望大家都不會遇到&#xff09;&#x1f602;&#x1f604; 在給手機 Root 或刷機時&#xff0c;線刷 9008 指的是利用 高通 9008 模式…

單機上使用docker搭建minio集群

單機上使用docker搭建minio集群 1.集群安裝1.1前提條件1.2步驟指南1.2.1安裝 Docker 和 Docker Compose&#xff08;如果尚未安裝&#xff09;1.2.2編寫docker-compose文件1.2.3啟動1.2.4訪問 2.使用2.1 mc客戶端安裝2.2創建一個連接2.3簡單使用下 這里在ubuntu上單機安裝一個m…

怎么在Github上readme文件里面怎么插入圖片?

環境&#xff1a; Github 問題描述&#xff1a; 怎么在Github上readme文件里面怎么插入圖片&#xff1f; https://github.com/latiaoge/AI-Sphere-Butler/tree/master 解決方案&#xff1a; 1.相對路徑引用 上傳圖片到倉庫 將圖片文件&#xff08;如 .png/.jpg&#xff…

Elasticsearch除了用作查找以外,還能可以做什么?

前言 Elasticsearch用于實時數據分析、日志存儲、業務智能等。還有日志與監控、多租戶和安全性。以及應用場景包括日志分析、公共數據采集、全文搜索、事件數據、數據可視化。處理錯誤拼寫和支持變體&#xff0c;不過這些可能還是屬于搜索優化。企業搜索、日志管理、應用監控、…

AIGC(生成式AI)試用 22 -- 跟著清華教程學習 - DeepSeek:從入門到精通

目標&#xff1a; 跟著清華教程學習DeepSeek同樣的問題分別嘗試使用DeepSeek和文心一言進行提問嘗試使用輔助工具完成學習中遇到的問題 個人理解&#xff1a; - AI&#xff0c;AI思維&#xff0c;像人一樣思考&#xff0c;越來越像人&#xff1f;參考數據宏大&#xff0c;思考…

[Windows] 全國油價實時查詢,可具體到城市

[Windows] 全國油價實時查詢&#xff0c;可具體到城市 鏈接&#xff1a;https://pan.xunlei.com/s/VOJnS3aOPeBwGaSvS0O0E1hwA1?pwdx83j# 出于代碼練習的目的&#xff0c;調用公共免費api做的py程序&#xff0c;已經一鍵打包&#xff0c;雙擊啟動即可 使用&#xff1a;選擇…

【并發編程】線程池任務拋異常會怎么樣?

一、先說結論 得看線程池的實現&#xff0c;JUC 的線程池&#xff08;ThreadPoolExecutor&#xff09;的話 不會影響其他的線程若是 submit 方法&#xff0c;或者任務為 future 任務&#xff0c;異常只有在 get 的時候才會拋出若是 execute runnable 任務&#xff0c;異常就…

本地部署deepseek-r1 ollama+anythingllm

本期筆者帶給大家部署一個本地私有化知識庫&#xff0c;簡單明了&#xff0c;直接步入主題&#xff0c;需要讀者可以繼續關注支持一下啊&#xff01; 目錄 背景步驟 一、環境準備二、Ollama環境部署三、AnythingLLM安裝 總結 開始下載應用&#xff1a; 操作系統&#xff1a…

JAVA-Exploit編寫(13-15)--JAVAFX-GUI檢測工具編寫實現

目錄 一,JAVAFX-GUI單個漏洞檢測編寫 1.1 綁定事件 1.2 Thinkphp5_Rce編寫 1.3 編寫利用類 1.4 Thinkphp2x_Rce編寫 1.5 單個漏洞檢測GUI工具完整代碼 二,JAVAFX-GUI單個漏洞批量檢測編寫 2.1 編寫利用反射類 2.2 批量檢測漏洞完整GUI工具代碼 三,JAVAFX-GUI…

mysql-Innodb記錄結構深度解析

Innodb記錄結構 InnoDB記錄結構深度解析一、InnoDB存儲基礎單元&#xff1a;頁&#xff08;Page&#xff09;二、行格式&#xff08;Row Format&#xff09; 三、核心行格式詳解1. Compact行格式結構組成&#xff1a; 2. Redundant行格式&#xff08;兼容舊版本&#xff09;核心…

Deepin(Linux)安裝MySQL指南

1.下載 地址&#xff1a;https://downloads.mysql.com/archives/community/ 2.將文件解壓到 /usr/local 目錄下 先cd到安裝文件所在目錄再解壓&#xff0c;本機是cd /home/lu01/Downloads sudo tar -xvJf mysql-9.2.0-linux-glibc2.28-x86_64.tar.xz -C /usr/local3.創建軟鏈…

ZT9 游游的字母翻倍

描述 游游拿到了一個長度為n的字符串&#xff0c;她每次操作會選擇一個區間[l,r]&#xff0c;將第l個字母到第r個字母各重復一次&#xff0c;插入到該字母的后面。 例如&#xff0c;對于字符串"abcd"&#xff0c;若選擇區間[2,3]進行操作&#xff0c;字符串將變成&qu…

Visual Studio更新說明(關注:.NET+AI生產力)

Ver V0.0&#xff1a;Visual Studio 2022 v17.12更新:.NET9AI生產力 AI插件推薦 &#xff08;1&#xff09;騰訊云AI代碼手&#xff08;內含了DeepSeek-R1&#xff09;&#xff0c;目前免費&#xff0c;但收費我也可能會買。 AI插件!推薦 &#xff08;1&#xff09;百度的…

C++ 設計模式-訪問者模式

C++訪問者模式 一、模式痛點:當if-else成為維護噩夢 開發動物園管理系統,最初的需求很簡單: class Animal {}; class Cat : public Animal {}; class Dog : public Animal {};// 處理動物叫聲 void makeSound(Animal* a) {if (auto c = dynamic_cast<Cat*>(a)) {st…

QEMU源碼全解析 —— 內存虛擬化(17)

接前一篇文章:QEMU源碼全解析 —— 內存虛擬化(16) 本文內容參考: 《趣談Linux操作系統》 —— 劉超,極客時間 《QEMU/KVM源碼解析與應用》 —— 李強,機械工業出版社 QEMU內存管理模型

java基于數組實現隊列(四)

概述 實現我上一篇博客中提到的 實際上&#xff0c;就是用synchronized代碼塊解決線程安全問題&#xff0c;以及利用wait()、notify()實現線程阻塞、喚醒。 實現 pollV3() private Object lockBySynchronizednew Object();public int pollV3() {synchronized (lockBySynchr…

linux -對文件描述符的操作dup、fcntl有五種

dup #include<unistd.h> int dup(int oldfd);作用&#xff1a;復制一個新的文件描述符fd 3, int fd1 dup(fd);f指向的是a.txt,fd1指向的也是a.txt從空閑的文件描述符表中找一個最小的作為新的拷貝的文件描述符返回&#xff1a;成功返回新的文件描述符&#xff0c;失敗…

DeepSeek各模型現有版本對比分析

文章目錄 一、基礎模型系列&#xff1a;V1 到 V3 的演進二、專用模型系列&#xff1a;推理與多模態三、版本選型與商業化趨勢 DeepSeek作為最近特別火爆的模型&#xff0c;本文將對DeepSeek現有的主要版本進行對比分析,涵蓋參數規模、訓練數據、功能改進、應用場景和性能表現等…

深入解析:在Spring Boot中集成MyBatis Plus實現高效數據庫操作

前后端微服務商城項目&#xff0c;手把手教學&#xff01; 在Spring Boot中集成第三方框架&#xff0c;實際上是非常常見的一種做法。Spring Boot自帶了很多開箱即用的功能&#xff0c;但在實際項目開發中&#xff0c;我們經常需要借助一些第三方框架來實現更為復雜的功能。比如…

現場可以通過手機或者pad實時拍照上傳到大屏幕的照片墻現場大屏電子照片墻功能

現場可以通過手機或者pad實時拍照上傳到大屏幕的照片墻現場大屏電子照片墻功能&#xff0c;每個人都可以通過手機實時拍照上傳到大屏幕上,同時還可以發布留言內容&#xff0c;屏幕上會同步滾動播放展示所有人的照片和留言。相比校傳統的照片直播功能更加靈活方便&#xff0c;而…