文章参考: C++学习笔记——CODspielen
文件操作 文本操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 #include <iostream> #include <string> #include <fstream> using namespace std;void test01 () { ofstream ofs; ofs.open ("text01.txt" , ios::out); ofs << "张三" << endl; ofs << "男" << endl; ofs << "18岁" << endl; ofs.close (); } void test02 () { ifstream ifs; ifs.open ("text01.txt" ,ios::in); if (!ifs.is_open ()) { cout << "文件打开失败" << endl; return ; } string buf; while (getline (ifs, buf)) { cout << buf << endl; } ifs.close (); } int main () { test01 (); test02 (); return 0 ; }
二进制操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <string> #include <fstream> using namespace std;class Person { public : char m_Name[64 ]; int m_Age; }; void test03 () { ofstream ofs ("person.txt" , ios::out | ios::binary) ; Person p = { "李四" , 28 }; ofs.write ((const char *)&p, sizeof (Person)); ofs.close (); } void test04 () { ifstream ifs; ifs.open ("person.txt" , ios::in | ios::binary); if (!ifs.is_open ()) { cout << "文件打开失败" << endl; return ; } Person p; ifs.read ((char *)&p, sizeof (Person)); cout << "姓名:" << p.m_Name << "\t" << "年龄:" << p.m_Age << endl; ifs.close (); }
新特性 易用性的改进 auto 不建议滥用,方便直接写出类型的就直接写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 double func01 () { return 1.1 ; } struct Test01 { int m_a; string m_b; }; void test01_01 () { int a = 1 ; auto b = 1 ; auto c = func01 (); Test01 str; auto d = str; } void func02 (vector<int > &v) { for (vector<int >::iterator it = v.begin (); it != v.end (); it++) { } for (auto ii = v.begin (); ii != v.end (); ii++) { } } auto func14 (int i) { if (i == 1 ) { return i; } else { return func14 (i - 1 ) + i; } }
decltype 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <iostream> #include <string> #include <typeinfo> #include <vector> using namespace std;enum { OK, ERROR } flag; void test02_01 () { int i; decltype (i) j = 0 ; cout << typeid (j).name () << endl; cout << typeid (j).hash_code () << endl; float a; double b; decltype (a + b) c; cout << typeid (c).name () << endl; vector<int > tmp; decltype (tmp.begin ())k; for (k = tmp.begin (); k != tmp.end (); k++) { } decltype (flag) flag2; cout << typeid (flag2).name () << endl; cout << typeid (flag2).hash_code () << endl; } int main () { test02_01 (); return 0 ; }
追踪函数的返回类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <string> #include <typeinfo> using namespace std;int func03 (int a, int b) { return a + b; } auto func04 (int a, double b) ->int { return a + b; } auto func05 (int a, double b) ->decltype (a + b) { return a + b; } void test03_01 () { int a = 10 ; double b = 9.8 ; auto c = func04 (a, b); auto d = func05 (a, b); cout << "c= " << c << " typeid= " << typeid (c).name () << endl; cout << "d= " << d << " typeid= " << typeid (d).name () << endl; } template <class T1, class T2>auto mul (const T1 &t1, const T2 &t2) ->decltype (t1 * t2) { return t1 * t2; } void test03_02 () { auto m = 8 ; auto n = 12.6 ; auto k = mul (m, n); cout << "k= " << k << " typeid= " << typeid (k).name () << endl; }
初始化列表和成员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 class A { public : int m_a; int m_b; public : A (int i, int j) :m_a (i), m_b (j) { } }; class B { public : int m_a{1 }; int m_b = 2 ; string m_name { "Tom" }; A tmp{ 10 , 20 }; }; void test04_01 () { B obj; cout << obj.m_a << " " << obj.m_b << " " << obj.m_name << " " << obj.tmp.m_a << " " << obj.tmp.m_b << endl; } struct Test04_01 { int a; int b; string name; }; void test04_02 () { Test04_01 t = { 1 , 2 , "Jerry" }; int a1 = 2 ; int a2 = { 3 }; int a3{ 4 }; int arr1[] = { 1 , 2 , 3 }; int arr2[]{ 1 , 2 , 3 , 4 }; vector<int > arr3{ 1 , 2 , 3 }; } void test04_03 () { const int a = 1024 ; char b = a; printf ("%d \n" , b); }
基于范围的for循环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 template <class T>void func05_01 (T &a) { for (auto temp : a) { cout << temp << " " ; } cout << endl; } void test05_01 () { int a[]{ 1 ,2 ,3 ,4 ,5 }; int len = sizeof (a) / sizeof (a[0 ]); for (int i = 0 ; i < len; i++) { int temp = a[i]; temp *= 2 ; cout << temp << " " ; } cout << endl; for (auto temp : a) { temp *= 2 ; cout << temp << " " ; } cout << endl; for (int i = 0 ; i < len; i++) { int &temp = a[i]; temp *= 2 ; cout << temp << " " ; } cout << endl; for (auto &temp : a) { temp *= 2 ; cout << temp << " " ; } cout << endl; func05_01 (a); }
静态断言 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #include <string> #include <cassert> using namespace std;void test06_01 () { bool flag = false ; assert (!flag); cout << "hello world" << endl; } void test06_02 () { static_assert (sizeof (void *) == 4 , "64位系统不支持" ); cout << "hello C++ 11" << endl; }
noexcept修饰符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void func07_01 () { throw 1 ; } void func07_02 () throw () { throw 1 ; } void func07_03 () noexcept { throw 1 ; }
🚀noexcept 和 try/catch:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <stdexcept> class SafeDivide {public : static double divide (double numerator, double denominator) noexcept { if (denominator == 0 ) { return 0 ; } return numerator / denominator; } }; class UnsafeDivide {public : static double divide (double numerator, double denominator) { if (denominator == 0 ) { throw std::invalid_argument ("Denominator cannot be zero." ); } return numerator / denominator; } }; int main () { double result1 = SafeDivide::divide (10 , 0 ); std::cout << "Result with SafeDivide: " << result1 << '\n' ; double result2; try { result2 = UnsafeDivide::divide (10 , 0 ); } catch (const std::invalid_argument& e) { std::cout << "Caught exception: " << e.what () << '\n' ; result2 = 0 ; } std::cout << "Result with UnsafeDivide: " << result2 << '\n' ; return 0 ; }
nullptr的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 void func08_01 (int a) { cout << __LINE__ << endl; } void func08_01 (int *a) { cout << __LINE__ << endl; } void test08_01 () { int *p = NULL ; int *p2 = 0 ; int *p3 = nullptr ; func08_01 (0 ); func08_01 (NULL ); func08_01 (nullptr ); func08_01 (p); func08_01 (p2); func08_01 (p3); int a = NULL ; if (p == p3) { cout << "equal" << endl; } }
🚩强类型枚举 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 enum class Status { OK, Error }; enum struct Status2 { OK, Error }; enum class Status3 : char { OK = 3 , Error = 4 }; enum class Status4 : long long { OK, Error }; void test09_01 () { Status flag = Status::OK; Status2 flag2 = Status2::Error; Status3 flag3 = Status3::OK; Status3 flag4 = Status3::Error; printf ("%d %d %d %d\n" , flag, flag2, flag3, flag4); cout << sizeof (Status::OK) << endl; cout << sizeof (Status2::OK) << endl; cout << sizeof (Status3::OK) << endl; cout << sizeof (Status4::OK) << endl; }
优点:
类型安全 :强类型枚举提供了更强的类型安全保障,确保了不同枚举类型的值不能隐式转换,减少了类型混淆的错误。作用域限制 :强类型枚举不会污染外围作用域,枚举值被限定在枚举类的作用域内。可读性 :强类型枚举通过明确的名称限定提供了更好的代码可读性,避免了枚举值在同一作用域下的潜在冲突。命名空间支持 :强类型枚举可以包含在命名空间中,避免枚举值与全局变量冲突。与类集成 :可将强类型枚举作为类成员或与类其他成员一起使用,提高类的封装性和数据完整性。constexpr支持 :强类型枚举可以与constexpr结合使用,使得枚举值可以在编译时进行计算。缺点:
隐式转换限制 :缺少了隐式转换的能力,这是在需要将强类型枚举值转换为整数类型时的一个不便。常量表达式 constexpr 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 int getNum () { return 3 ; } const int getNum2 () { return 3 ; } constexpr int getNum3 () { return 3 ; } enum class Num_e { e1 = getNum3 (), e2 }; void test10_01 () { constexpr int tmp = getNum3 (); const int tmp1 = getNum3 (); cout << tmp << endl; enum class Num_e1 { e1 = tmp, e2 = tmp1 }; printf ("%d, %d, %d, %d\n" , Num_e::e1, Num_e::e2, Num_e1::e1, Num_e1::e2); } constexpr int func10_01 () { static_assert (1 , "fail" ); constexpr int a = 1 ; return a; } int a_10 = 12 ;constexpr int func10_02 () { return a_10; } constexpr int func10_03 () { return getNum3 (); } void test10_02 () { int m_a = func10_01 (); int m_b = func10_02 (); int m_c = func10_03 (); cout << m_a << " " << m_b << " " << m_c << endl; } class Date { public : constexpr Date (int y, int m, int d) : year(y), month(m), day(d) { } int GetYear () const { return year; } int GetMonth () const { return month; } int GetDay () const { return day; } private : int year; int month; int day; }; void test10_03 () { constexpr Date obj (2077 , 8 , 8 ) ; cout << obj.GetYear () << "年" << obj.GetMonth () << "月" << obj.GetDay () << "日" << endl; } template <class T >constexpr T pi = T (3.1415926535897932385L );void test10_04 () { cout << pi<int > << endl; cout << pi<double > << endl; }
原生字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main () { cout << R"(hello world)" << endl; cout << R"(hello \n world)" << endl; string str = R"(hello \4 \r abc, mike hello\n)" ; cout << endl; cout << str << endl; return 0 ; }
输出结果:
1 2 3 4 5 6 7 hello world hello \n world hello \4 \r abc, mike hello\n
🚩类的改进 继承构造 格式 using Base::Base;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class A1 { public : A1 (int x, int y) { a = x; b = y; } protected : int a; int b; }; class B1 : public A1{ public :#if 0 B12 (int x, int y):A12 (x, y) { } #endif using A1::A1; void show () { cout << "a= " << a << ", b= " << b << endl; } }; void test12_01 () { B1 obj (77 , 44 ) ; obj.show (); }
委托构造 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class A2 { public : A2 () :A2 (1 , 'a' ) { } A2 (int x) :A2 (x, 'b' ) { } A2 (char x) :A2 (16 , x) { } A2 (int x, char y) :a (x), b (y) { } public : int a; char b; }; void test12_02 () { A2 obj; cout << obj.a << obj.b << endl; A2 obj1 (5 ) ; cout << obj1.a << obj1.b << endl; A2 obj2 ('c' ) ; cout << obj2.a << obj2.b << endl; }
继承控制:final和override 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class A3 final { public : int a; }; class A5 { public : virtual void func () final = 0 ; }; class A6 : public A5{ public : }; class B2 { public : virtual void func (int a) = 0 ; }; class B3 : public B2{ public : virtual void func (int a) override { } };
类默认函数的控制:=default和=delete函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 class X { public : X () = default ; X (int i) { a = i; } int a; }; class X1 { public : X1 (); X1 (int i) { a = i; } int a; }; X1::X1 () = default ; class X2 { public : X2 () { cout << "X2的默认构造的调用" << endl; } X2 (const X2 &x) = delete ; X2 &operator = (const X2 &x) = delete ; int func () = delete ; X2 (int x) = delete ; void *operator new (size_t t) = delete ; void *operator new [](size_t t) = delete ; void operator delete (void *ptr) = delete ; }; void test12_03 () { X2 obj1; X2 obj3; }
模板的改进 右尖括号>改进 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <int i> class C1 { }; template <class T > class C2 { }; void test13_01 () { C2<C1<8 >> obj1; }
模板的别名 using 格式 using 别名 = 原类型;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 typedef int int32; using my_int = int ; void test13_02 () { cout << is_same<int32, my_int>::value << endl; cout << typeid (int32).name () << endl; cout << typeid (my_int).name () << endl; int32 a = 1 ; my_int b = 2 ; }
函数模板的默认模板参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 void test13_03 (int a = 3 ) { cout << a << endl; } template <class T = int >class C3{ public : T a; }; template <class T = int >void test13_04 (T a) { cout << a << endl; } template <class T1 = int , class T2 = double > class C4{ public : T1 t1; T2 t2; }; template <class T1 , class T2 > class C5 { public : T1 t1; T2 t2; }; template <class T1 , class T2 = int > class C7{ public : T1 t1; T2 t2; }; template <class T1 = int , class T2 = double > void test13_05 (T1 a, T2 b){ cout << a << b << endl; } template <class T1 , class T2 >void test13_06 (T1 a, T2 b) { cout << a << b << endl; } template <class T1 = int , class T2>void test13_07 (T1 a, T2 b){ cout << a << b << endl; } template <class T1 , class T2 = int >void test13_08 (T1 a, T2 b){ cout << a << b << endl; }
可变参数模板(难点) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 template <class ... T> void func001 (T ... a) { cout << "num= " << sizeof ...(a) << endl; } void test13_09 () { func001 <int >(10 ); func001 <int , double , char >(3 , 3.14 , 'd' ); func001 (11 , 13.5 , 34 , 'c' ); }
递归展开模板参数包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 void debug () { cout << "empty" << endl; } #if 0 template <class T>void debug (T t) { cout << "last = " << t << endl; } #endif template <class T1, class ... T2>void debug (T1 t1, T2 ... t2) { cout << t1 << " " ; debug (t2...); } void test13_10 () { debug (1 , 2 , 3 , 4 ); cout << endl; debug (22 , "Tom" , 3.14 , 'c' ); cout << endl; }
非递归展开模板参数包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <class T>void print (T x) { cout << x << " " ; } template <class ... T>void expand (T ... t) { int a[] = { (print (t), 0 )... }; } void test13_11 () { expand (5 , 6 , 7 , 8 ); cout << endl; }
注:关于 (print (t), 0)
,每个逗号运算符中的 print(t)
调用都会打印一个参数,然后返回0(因为这个数组 a 的成员元素类型为 int)。数组中的每个元素都使用一个 0
进行初始化(为1为2都可以,数组仅作存储用途)。括号用来确保逗号运算符的作用。
继承方式展开模板参数包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 template <class ... T>class Car { }; template <>class Car <>{ }; template <class Head , class ... Tail>class Car <Head, Tail...> : public Car<Tail...> { public : Car () { cout << "type= " << typeid (Head).name () << endl; } }; void test13_12 () { Car<int , double , char *, float > Ferrari; }
模板类递归和特化方式展开参数包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 template <int ... i>class Test { }; template <>class Test <>{ public : static const int val = 1 ; static const int sum = 0 ; }; template <int first, int ... last>class Test <first, last...>{ public : static const int val = first * Test<last...>::val; static const int sum = first + Test<last...>::sum; }; void test13_13 () { Test<2 , 3 , 4 , 5 ,6 > t; cout << t.val << endl; cout << t.sum << endl; cout << Test<2 , 3 , 4 , 5 , 6 >::val << endl; cout << Test<2 , 3 , 4 , 5 , 6 >::sum << endl; }
变参模板的应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 void printX () {} template <class T, class ...Types>void printX (const T &firstArg, const Types &...args) { cout << firstArg << " " ; printX (args...); } void test13_14 () { printX (45 , 9.8 , "abc" , 'm' ); cout << endl; } int maximun (int n) { return n; } template <class ...T>int maximun (int n, T...args) { return max (n, maximun (args...)); } void test13_15 () { cout << maximun (57 , 48 , 60 , 100 , 20 , 18 ) << endl; cout << max ({ 57 , 48 , 60 , 100 , 20 , 18 }) << endl; } template <class T>int sum (T t) { return t; } template <class T1, class ... T2>int sum (T1 first, T2...last) { return first + sum (last...); } void test13_16 () { cout << sum (33 , 16 , 28 , 55 , 100 ) << endl; } template <class T , class U >struct A13 { T t; U u; }; template <class T >using B13 = A13<T, int >;
右值引用及其应用 右值引用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 int &func01_01 () { static int tmp; return tmp; } void test01_01 () { int a; int &b = a; const int &c = a; const int &d = 1 ; int &e = func01_01 (); const int &f = func01_01 (); const int tmp = 10 ; const int &g = tmp; } int func01_02 () { return 8 ; } void test01_02 () { int &&a = 1 ; int &&b = func01_02 (); int i = 2 ; int j = 3 ; int &&c = i + j; int k = 6 ; } void func01_03 (int &tmp) { cout << "左值 = " << tmp << endl; } void func01_03 (int &&tmp) { cout << "右值 = " << tmp << endl; } void test01_03 () { int a = 10 ; func01_03 (a); func01_03 (11 ); }
返回值优化技术与移动语义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 class MyString { public : MyString (const char *tmp = "abc" ) { len = strlen (tmp); str = new char [len + 1 ]; strcpy_s (str, len + 1 , tmp); cout << "有参构造的调用:str =" << str << endl; } MyString (const MyString &tmp) { len = tmp.len; str = new char [len + 1 ]; strcpy_s (str, len + 1 , tmp.str); cout << "拷贝构造的调用:str =" << tmp.str << endl; } MyString (MyString &&t) { len = t.len; str = t.str; cout << "移动构造的调用:str =" << t.str << endl; t.str = nullptr ; } MyString &operator = (const MyString &tmp) { if (&tmp == this ) { return *this ; } len = 0 ; delete []str; len = tmp.len; str = new char [len + 1 ]; strcpy_s (str, len + 1 , tmp.str); cout << "运算符重载的调用:str =" << tmp.str << endl; return *this ; } MyString &operator = (MyString &&t) { if (&t == this ) { return *this ; } len = 0 ; delete []str; len = t.len; str = t.str; cout << "移动赋值函数的调用:str =" << t.str << endl; t.str = nullptr ; return *this ; } ~MyString () { cout << "析构函数的调用," ; len = 0 ; if (str != nullptr ) { cout << "已操作delete,str = " << str; delete []str; str = nullptr ; } cout << endl; } private : char *str = nullptr ; int len = 0 ; }; MyString func () { MyString obj ("CODspielen" ) ; cout << "&obj (取地址) = " << (void *)&obj << endl; return obj; } void test02_01 () { MyString s = func (); cout << "&s (取地址) = " << (void *)&s << endl; } void test02_02 () { MyString &&s1 = func (); cout << "&s1 (取地址) = " << (void *)&s1 << endl; } void test02_03 () { MyString s2 ("CODplay" ) ; s2 = func (); cout << "&s2 (取地址) = " << (void *)&s2 << endl; }
move和完美转发forward 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 void test02_04 () { int a = 9 ; int &&b = move (a); cout << "b= " << b << endl; } template <class T>void func02_01 (const T &) { cout << "const T &" << endl; } template <class T>void func02_01 (T &) { cout << "T &" << endl; } template <class T>void func02_01 (T &&) { cout << "T &&" << endl; } template <class T>void forward_val (const T &tmp) { func02_01 (tmp); } template <class T>void forward_val (T &tmp) { func02_01 (tmp); } void test02_05 () { int a = 0 ; const int &b = 1 ; forward_val(a); forward_val(b); forward_val(12 ); } typedef const int T;typedef T & TR;TR &v = 1 ; template <class T>void forward_val1 (T &&tmp) { func02_01 (forward<T>(tmp)); } void test02_06 () { int a = 0 ; const int &b = 1 ; forward_val1(a); forward_val1(b); forward_val1(12 ); }
🚩智能指针 C++11中有unique_ptr
, shared_ptr
, weak_ptr
等智能指针,定义在<memory>
中; 可以对动态资源进行管理,在任何情况下,已构造的对象会销毁,即它的析构函数最终会被调用。
unique_ptr unique_ptr
是一个模板,创建的是对象 ,不用加 *
。持有对对象的独有权 ,同一时刻只能有一个 unique_ptr
绑定给定的对象(通过禁止拷贝语义,只用移动语义 move
来实现)。 unique_ptr
生命周期:从指针创建开始,直到离开作用域就释放 。离开作用域时,若其指向对象,则这个对象被销毁,默认使用 delete
操作,用户也可以指定其他操作。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 void test03_01 () { unique_ptr<int > up1 (new int (11 )) ; cout << "*up1= " << *up1 << endl; unique_ptr<int > up2 = move (up1); cout << "*up2= " << *up2 << endl; } class Test03_01 { public : ~Test03_01 () { cout << "析构函数的调用" << endl; } }; void test03_02 () { unique_ptr<Test03_01> up3 (new Test03_01) ; up3 = nullptr ; up3.reset (); cout << endl; } void test03_03 () { unique_ptr<int > up1 (new int (11 )) ; up1.reset (); up1.reset (new int (22 )); cout << "*up1= " << *up1 << endl; int *p = up1.release (); cout << "*p= " << *p << endl; delete p; }
shared_ptr 和 unique_ptr
相反,shared_ptr
允许多个智能指针的对象共享同一块堆区 分配的内存,通过引用计数实现。 如果最后一个这样的指针被销毁,也就是计数变成 0,这个对象才会被自动删除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void test03_04 () { shared_ptr<int > sp1 (new int (8 )) ; shared_ptr<int > sp2 = sp1; cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << endl; cout << "*sp1 = " << *sp1 << " *sp2 = " << *sp2 << endl; sp1.reset (); cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << endl; cout << "*sp2 = " << *sp2 << endl; sp2.reset (); cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << endl; }
weak_ptr 配合 shared_ptr
使用,可以从一个 shared_ptr
或者另一个 weak_ptr
对象构造,它的构造和析构不会引起引用计数的变化 。 没有重载 *
和 ->
,但可以使用 lock
获得一个可用的 shared_ptr
对象。 weak_ptr
可以指向 shared_ptr
指针指向的内存空间,但是并不拥有该内存 。如果使用 weak_ptr
的成员函数 lock
,则可以返回其指向内存的一个 shared_ptr
对象,且在所指向内存已经无效时,返回空值 nullptr
。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 void test03_05 () { shared_ptr<int > sp1 (new int (6 )) ; shared_ptr<int > sp2 = sp1; weak_ptr<int > wp = sp1; cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << " 计数器3 = " << wp.use_count () << endl; shared_ptr<int > sp3 = wp.lock (); cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << " 计数器3 = " << wp.use_count () << " 计数器4 = " << sp3.use_count () << endl; cout << "*sp1 = " << *sp1 << " *sp2 = " << *sp2 << " *sp3 = " << *sp3 << endl; sp1.reset (); cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << " 计数器3 = " << wp.use_count () << " 计数器4 = " << sp3.use_count () << endl; sp2.reset (); cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << " 计数器3 = " << wp.use_count () << " 计数器4 = " << sp3.use_count () << endl; sp3.reset (); cout << "计数器1 = " << sp1.use_count () << " 计数器2 = " << sp2.use_count () << " 计数器3 = " << wp.use_count () << " 计数器4 = " << sp3.use_count () << endl; wp.reset (); shared_ptr<int > tmp = wp.lock (); if (tmp == nullptr ) { cout << "堆区空间已经释放" << endl; } }
闭包 闭包定义:带有上下文 的函数,有状态 的函数,也是一个类 。
带有状态,即拥有自己的变量 ,而不是全局变量,也不是传进来的变量。 函数和状态捆绑,就形成了闭包。 闭包的状态捆绑,必须发生在运行时 。 闭包的实现:仿函数、bind 绑定器、Lambda 表达式 。仿函数 仿函数 functor
(不是 C++11 的新内容)就是使一个类的使用看上去像一个函数,其实现就是在类中实现一个 operator()
,这个类就有了类似的函数行为,就是一个仿函数类了。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class MyFunc { public : MyFunc (int i) :r (i) { } int operator () (int tmp) { return tmp + r; } bool operator () (int a, int b) { return (a > b && b > r); } private : int r; }; void test04_01 () { MyFunc obj (8 ) ; cout << obj (5 ) << endl; cout << obj (23 , 44 ) << endl; cout << obj (77 , 44 ) << endl; }
function 与 bind 的使用 function C++中,可调用的实体主要包括:函数、函数指针、函数引用、可隐式转换为函数指定的对象,或者实现了 operator()
的对象。 C++11 中,新增了 std::function
类模板(头文件 <functional>
),是对 C++中所有可调用实体的一种案例类型的打包。 通过指定参数模板,可以统一处理函数、函数对象、函数指针,并允许保存和延迟执行它们。 function
对象最大的作用:实现函数回调,但是不能用来检查相等/不相等,不过可以与 NULL
/ nullptr
比较。格式 function<void(int)>
表示返回类型为 void,接受一个 int 参数的可调用对象。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 void func04_01 () { cout << __func__ << "的调用" << endl; } class Test41 { public : static int test_func (int a) { cout << __func__ << "的调用," << a << endl;; return a * 2 ; } }; class Test42 { public : int operator () (int a) { cout << __func__ << "的调用," << a << endl;; return a * 3 ; } }; void test04_02 () { function<void (/*没参数就不用写,或者写void ; */)> f1 = func04_01; f1 (); function <int (int )> f2 = Test41::test_func; cout << f2 (19 ) << endl;; Test42 obj; function<int (int )> f3 = obj; cout << f3 (7 ) << endl; }
🤔注:可调用实体
1 2 3 4 void myFunction (int x) { } myFunction (10 );
函数指针 : 函数指针是指向函数的指针,可以通过函数指针来调用函数。函数指针的类型必须与目标函数的类型相匹配。1 2 void (*funcPtr)(int ) = myFunction; funcPtr (10 );
函数引用 : 函数引用是函数的别名,可以通过函数引用来调用函数。函数引用在声明时必须初始化 ,并且不能更改引用目标 。1 2 void (&funcRef)(int ) = myFunction;funcRef (10 );
可隐式转换为函数指针的对象: 某些对象可以隐式转换为函数指针,例如通过 std::function
或 std::mem_fn
包装的函数对象。1 2 std::function<void (int )> funcObj = myFunction; funcObj (10 );
实现了 operator()
的对象 : 这些对象被称为函数对象或仿函数(Functor)。它们通过重载 operator()
来实现类似函数调用的行为。1 2 3 4 5 6 7 8 struct MyFunctor { void operator () (int x) { } }; MyFunctor functor; functor (10 );
bind 预先把可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体,在回调函数中常用。 C++11 中,bind
的参数个数不受限,绑定具体哪些参数也不受限,由用户指定,非常灵活。绑定的参数可以是占位符(比如 placeholder::_2
) 同样在头文件 <functional>
中,基本语法为 std::bind(callable, arg1, arg2, ..., argN)
,其中 callable
表示可调用对象,函数返回类型为 function<RetType>(ArgsType)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 void func04_02 (int x, int y) { cout << x << " " << y << " " << endl; } void test04_03 () { bind (func04_02, 11 , 22 )(); bind (func04_02, placeholders::_1, placeholders::_2)(5 , 6 ); bind (func04_02, _1, _2)(17 , 18 ); bind (func04_02, 33 , _3)(77 , 88 , 44 , 55 ); bind (func04_02, _2, _1)(99 , 77 ); } class Test43 { public : void func (int x, int y) { cout << "x = " << x << ",y = " << y << " " << endl; } int a; }; using namespace placeholder;void test04_04 () { Test43 obj; function<void (int , int )> f1 = bind (&Test43::func, &obj, _1, _2); f1 (98 , 87 ); function<int & ()> f2 = bind (&Test43::a, &obj); f2 () = 111 ; cout << "obj.a = " << obj.a << endl; }
🚩Lambda 表达式 lambda表达式是一个匿名函数,基于数学中的λ演算得名。 C++11中的lambda表达式用于定义并创建匿名的函数对象 ,以简化编程工作;通常配合回调函数使用。
💭Lambda 表达式的结构 :
1 2 3 4 []()mutable exeption ->int { };
[]
:捕获列表,标识一个 Lambda 表达式的开始,不能省略。可认为是函数名。捕获外面的参数属性 (而非参数本身),相当于类的成员变量。()
:没有参数时可以省略,有参数时写在 () 里,和普通函数的参数写法一致。mutable
:用于修饰类的成员变量,允许在 const
成员函数中修改被 mutable
修饰的成员变量。
💭 []
内通常有:
空,无任何对象参数 =
,表示全部值传递&
,表示全部引用传递this
,类内成员变量,和全局变量a
,将 a 按值传递进行传递,默认为 const,如果要修改可以加上 mutable
在 ()
后&a
,将 a 按引用传递进行传递a, &b
,a 值传递,b 引用传递=, &a, &b
,除了 a 和 b 引用传递外,其余值传递(=
要放在前面)&, a, b
,除了 a 和 b 值传递外,其余引用传递(&
要放在前面)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 int tmp0 = 9 ; class Test44 { public : int i = 5 ; void func () { auto f1 = [=]() { cout << i << endl; cout << tmp0 << endl; }; f1 (); auto f2 = [&]() { cout << i << endl; cout << tmp0 << endl; }; f2 (); auto f3 = [this ]() { cout << i << endl; cout << tmp0 << endl; }; f3 (); } }; void test04_05 () { int a = 0 ; int b = 1 ; int c = 2 ; auto f1 = []() { }; f1 (); auto f2 = [a, b]() { cout << a << " " << b << endl; }; f2 (); auto f3 = [a, b](int x, int y) { cout << a << " " << b << endl; cout << x << " " << y << endl; }; f3 (14 , 16 ); auto f4 = [=]() { cout << a << " " << b << endl; }; f4 (); auto f5 = [&]() { cout << a << " " << b << endl; }; f5 (); auto f6 = [&, a]() { cout << a << " " << b << " " << c << endl; }; f6 (); auto f7 = [=, &b]() { cout << a << " " << b << " " << c << endl; }; f7 (); auto f8 = [=]() mutable { a++; cout << a << " " << b << " " << c << endl; cout << tmp0 << endl; }; f8 (); Test44 t; t.func (); }
🚀值传递和引用传递的区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void test04_06 () { auto a = 88 ; auto f1 = [=]() mutable { a += 10 ; cout << "a = " << a << endl; }; f1 (); cout << "a2 = " << a << endl; a = 222 ; f1 (); auto b = 66 ; auto f2 = [&]() { b += 10 ; cout << "b = " << b << endl; }; f2 (); cout << "b2 = " << b << endl; b = 333 ; f2 (); }
Lambda 表达式比仿函数更简洁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void test04_07 () { int tmp = 10 ; MyFunc obj (tmp) ; cout << obj (7 ) << endl; cout << obj (18 , 14 ) << endl; auto f = [tmp](int r) { return tmp + r; }; cout << f (8 ) << endl; int r = 8 ; auto f1 = [r](int a, int b) { return (a > b && b > r); }; cout << f1 (19 , 16 ) << endl; }
仿函数是编译器实现 Lambda 的一种方式,通过编译器将 Lambda 表达式转化为一个仿函数的对象。 Lambda 表达式可以视为仿函数的一种等价形式 。
💭Lambda 表达式的类型:
在 C++11 中是闭包类型,每个 Lambda 表达式会产生一个临时对象(右值)。因此严格来说,Lambda 表达式并非函数指针。 C++11 允许 Lambda 表达式向函数指针转换,但前提是 Lambda 表达式没有捕获任何变量 ,且函数指针指向的函数原型必须跟 Lambda 表达式有着相同的签名 (返回类型、参数列表)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 void test04_08 () { function<void (int )> f1 = [](int a) { cout << a << endl; }; f1 (100 ); function<int (int )> f2 = [](int a) { return a + 5 ; }; cout << f2 (110 ) << endl; function<int (int , int )> f3 = bind ( [](int a, int b) { return a * 2 + b; }, _2, _1 ); cout << f3 (10 , 8 ) << endl; auto f4 = [](int x, int y) -> int { return x + y; }; cout << f4 (3 , 5 ) << endl; decltype (f4) tmp = f4; cout << tmp (6 , 8 ) << endl; typedef int (*PFUC) (int , int ) ; PFUC p1 = f4; cout << p1 (10 , 19 ) << endl; }
✅注:易错点区分 使用函数指针(隐式转换,使用 auto
时结果一致 ):
1 2 3 4 5 6 7 8 9 10 11 12 void TestTransform () { int (*f4)(int ,int ) = [](int x, int y) -> int { return x + y; }; int (*p1)(int , int ) = f4; p1 (9 ,9 ); using funcPtr = int (*)(int , int ); funcPtr p2 = f4; p2 (9 ,9 ); }
直接使用 std::function
对象存储 Lambda 表达式(较复杂):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void TestTransform () { function<int (int , int )> f4 = [](int x, int y) -> int { return x + y; }; function<int (int , int )> p1 = f4; p1 (9 ,9 ); using FuncObj = function<int (int , int )>; FuncObj p2 = f4; p2 (9 ,9 ); int (*p3)(int , int ) = *f4.target <int (*)(int , int )>(); p3 (9 ,9 ); }
💡lambda 表达式与 for_each
(需要头文件 <algorithm>
结合使用):for_each(InputIterator first, InputIterator last, Function func)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 int tmp01 = 5 ;vector<int > nums; vector<int > largeNums; void pushLargeNums (int &n) { if (n > tmp01) { largeNums.push_back (n); } } void printNums (int &n) { cout << n << " " ; } void test04_09 () { for (int i = 0 ; i < 10 ; i++) { nums.push_back (i + 1 ); } for (auto it = nums.begin (); it != nums.end (); it++) { if (*it > tmp01) { largeNums.push_back (*it); } } cout << "传统方法打印1:" ; for (int i = 0 ; i < largeNums.size (); i++) { cout << largeNums[i] << " " ; } cout << endl; cout << "传统方法打印2:" ; for (auto it = largeNums.begin (); it != largeNums.end (); it++) { cout << *it << " " ; } cout << endl; cout << "for_each + 回调函数:" ; largeNums.clear (); for_each(nums.begin (), nums.end (), pushLargeNums); for_each(largeNums.begin (), largeNums.end (), printNums); cout << endl; cout << "for_each + lambda表达式:" ; largeNums.clear (); for_each ( nums.begin (), nums.end (), [&](int &n) { if (n > tmp01) { largeNums.push_back (n); } } ); for_each ( largeNums.begin (), largeNums.end (), [](int &n) { cout << n << " " ; } ); cout << endl; }
💭C++14 中的更新(泛型 Lambda):
在 C++11 中,Lambda 表达式的形式参数需要被声明为具体的类型,比如 (int x)
C++14 中引入了泛型 Lambda,允许形式参数声明中使用类型说明符 auto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 auto f = [](auto x, auto y) { return x + y; }; struct unnamed_lambda { template <class T, class U> auto operator () (T x, U y) const { return x + y; } }; auto lambda = unnamed_lambda{};auto lambda1 = [value = 1 ](){ return value; }; auto lambda2 = [](auto a){ return a; };