目錄
前言/背景
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的發展歷史
?2.列表初始化
2.1 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
#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 左值和右值
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;
3.2 左值引用和右值引用
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");
//const左值引用可以引用右值
const int& rr5 = 10;
const int& rr6 = x + y;
const double& rr7 = fmin(x, y);
const string& rr8 = string("11111");
//右值引用move左值
int&&rrx1= move(b);
int*&&rrx2= move(p);
int&&rrx3= move(*p);
string&&rrx4= move(s);
char&&rrx5= move(s[0]);
// 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 引用延長生命周期
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 左值和右值的參數匹配
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的知識還有很多,下篇博客我們將詳細講解右值引用和移動語義的應用!!!?