暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

C++11 语言特性和标准库 关键特性

林元皓 2020-04-22
482


C++11

C++11/14/17 引入了大量非常有用的特性,使代码更直观、安全、简洁、方便。C++11 特性是 C++20 以前更新最多的版本, C++14、C++17 特性更新少很多。 

在此总结一下C++11 语言特性和标准库。 

此处列举的仅是一部分较常用的特性,完整的列表还需参考官方文档或者微软的文档: 

https://docs.microsoft.com/en-us/previous-versions/hh567368(v=vs.140)?redirectedfrom=MSDN

C++11 关键特性

C++11特性:auto 自动推导说明符

auto 自动推导说明符,主要就是用来根据上下文自动推导声明的变量类型,从而不需要写冗余的类型,提高开发效率和减少代码量。

auto.cpp

  1. #include <algorithm>

  2. #include <vector>

  3. #include <iostream>

  4. #include <map>

  5. #include <string>

  6. #include <string.h>

  7. #include <stdint.h>

  8. #include <typeinfo>


  9. /*

  10. 1、用于声明变量或常量

  11. 2、用于声明的变量从表达式初始化

  12. 3、用在 range-for的C++新for循环语法里

  13. 4、用于模板函数的返回后缀语法的占位符

  14. */



  15. /////////////////////////////////////////////////////////////////////////////////////////////////////


  16. int64_t Add(int64_t first, int64_t second) {

  17. return first + second;

  18. }


  19. template<class T, class N>

  20. auto AddTemplate(T t, N n)->decltype(t + n) {

  21. return t + n;

  22. }


  23. /////////////////////////////////////////////////////////////////////////////////////////////////////


  24. int main(int argc, char const *argv[])

  25. {


  26. std::cout << "----------1、用于声明变量或常量---------------" << std::endl;

  27. auto i = 12; // int

  28. auto str = "hello vic.MINg"; // const char*

  29. auto ilist = { 1, 2, 3 }; // std::list

  30. auto d = 3.14; // double

  31. auto& d1 = d; // double&

  32. auto d2 = &d; // double*

  33. auto ivector = new std::vector<int>(); // std::vector<int>

  34. system("pause");


  35. std::cout << "----------2、用于声明的变量从表达式初始化---------------" << std::endl;

  36. auto istrlen = strlen(str) + 1; // 算术表达式

  37. auto func = [](int j) {std::cout << j << std::endl; }; // lambda 表达式

  38. // 应用在lambda

  39. auto print = [](const char* name) {

  40. std::cout << "name: " << name << std::endl;

  41. };

  42. print("vic.MINg");

  43. system("pause");


  44. std::cout << "----------3、用在 range-for的C++新for循环语法里---------------" << std::endl;

  45. for (auto one : { 1, 2, 3 }) {

  46. std::cout << "one: " << typeid(one).name() << ":" << one << std::endl;

  47. }


  48. std::map<std::string, int> p1 = { { "info",1 },{ "world",2 } };

  49. // std::map<>::value_type 类型,即std::pair<std::string,int>, 必须是auto&才不会创建新的 std::pair.

  50. // 也只有auto& 才可以改里面的值.

  51. for (auto& vt : p1) {

  52. auto& key = vt.first;

  53. auto& value = vt.second;

  54. value = 3;

  55. }

  56. for (auto ite : p1)

  57. std::cout << "key: " << ite.first << " second: " << ite.second << std::endl;

  58. // 注意这个是std::map<>::iterator,不是value_type, ite相当于指向value_type的共享指针.

  59. for (auto ite = p1.begin(); ite != p1.end(); ++ite) {

  60. auto& key = ite->first;

  61. auto& value = ite->second;

  62. int start = 0xa;

  63. value = start++;

  64. }

  65. for (auto ite : p1)

  66. std::cout << "key: " << ite.first << " second: " << ite.second << std::endl;

  67. system("pause");


  68. std::cout << "----------4、用于模板函数的返回后缀语法的占位符---------------" << std::endl;

  69. auto v1 = Add(1, 2); // v1: long long

  70. std::cout << "v1: " << typeid(v1).name() << std::endl;

  71. auto v2 = AddTemplate(8.9, -1); // v2: double

  72. std::cout << "v2: " << typeid(v2).name() << std::endl;

  73. system("pause");


  74. return 0;

  75. }

C++11特性:constexpr 常量表达式说明符

constexpr.cpp

  1. #include <algorithm>

  2. #include <vector>

  3. #include <stddef.h>

  4. #include <iostream>

  5. #include <string>

  6. #include <stdlib.h>

  7. #include <memory>

  8. #include <complex>


  9. /*

  10. constexpr 说明:

  11. 1、提供更加通用的常量表达式。

  12. 2、允许常量表达式包括用户定义的类型。

  13. 3、提供一种方法保证在编译时完成初始化。

  14. constexpr 语法:

  15. 1、constexpr 变量声明

  16. 2、constexpr 函数声明

  17. 3、constexpr 构造函数声明

  18. 4、用户自定义的字面常量

  19. */


  20. ////////////////////////////////////////////////////////////////////////////////////

  21. enum Flags { undo = 0, doing = 1, fail = 2, finish = 4 };


  22. // 给定的常量参数和简单运算可以在编译时得到常量结果.

  23. // 简单运算: 编译器能在编译器计算出结果的.(也就是编译不出错).

  24. constexpr int funFlags(Flags f1, Flags f2) {

  25. return f1 + f2;

  26. }


  27. constexpr std::complex<long double> operator""_b(long double d)

  28. {

  29. return { 3.14, d }; // complex is a literal type

  30. }


  31. ////////////////////////////////////////////////////////////////////////////////////


  32. int main(int argc, char const *argv[])

  33. {


  34. std::cout << "----------1、constexpr 变量声明--------------" << std::endl;

  35. // constexpr 类型 变量名 = 表达式; ( 表达式: 需要简单逻辑的常量表达式 )


  36. constexpr int x1 = fail | finish; // 编译器在编译时得出x1 结果 = 6

  37. const int x2 = fail | finish; // 编译器不能保证在编译时得结果.

  38. static_assert(x1 == 6, "x1 not 6"); // 静态断言,编译时断言.

  39. system("pause");


  40. std::cout << "----------2、constexpr 函数声明--------------" << std::endl;

  41. // 1、给定的常量参数和简单运算可以在编译时得到常量结果.

  42. // 2、注意要函数和变量声明都需要加 constexpr.

  43. // -- 变量不加 constexpr 不会在编译时计算结果.

  44. // -- 函数不加 constexpr 编译报错: function call must have a constant value in a constant expression


  45. constexpr int result = funFlags(undo, doing); // 结果 = 1

  46. static_assert(result == 1, "result not 1"); // 静态断言,编译时断言.

  47. system("pause");


  48. std::cout << "----------3、constexpr 构造函数声明--------------" << std::endl;

  49. // 需要简单逻辑的构造函数

  50. struct Point {

  51. int m_nX, m_nY;

  52. constexpr Point(int x, int y) : m_nX(x), m_nY(y) { }

  53. };


  54. // 调用构造函数获取实例时也需要声明constexpr

  55. constexpr Point pt[] = { Point(0,0), Point(1,1), Point(2,2) };

  56. constexpr int Y = pt[1].m_nY; // 结果 = 1

  57. //static_assert(Y == 1, "x not 1"); // 静态断言,在编译时断言.

  58. system("pause");


  59. std::cout << "----------4、用户自定义的字面常量--------------" << std::endl;

  60. // C++11新特性声明用户自定义字面常量 (user - defined literals)

  61. constexpr auto z = 1.0_b; // {(3.14L + 1.0L)}

  62. //std::cout << "1.0_b = " << z << std::endl;

  63. system("pause");


  64. // const vs constexpr

  65. // const

  66. // 1、声明变量时,可以不初始化值.

  67. // 2、如果声明的变量没初始化,编译器通常能初始化(不保证)。

  68. // 3、把const对象存放在编译器表格里,但是不会放入产生的代码(编译后的代码)里。

  69. // constexpr

  70. // 1. 声明变量时,必须有初始化值.

  71. // 2. 在编译时间计算初始化值。

  72. // 3. 把对象放入编译器表格里,只在需要的时候放入产生的代码里。


  73. return 0;

  74. }

C++11特性:copy-rethrow-exception 复制和重抛异常

复制和重抛异常在 C++11 里是用函数实现的所以并没有什么新的关键字说明符

copy-rethrow-exception.cpp

  1. #include <iostream>

  2. #include <string>

  3. #include <vector>

  4. #include <string.h>

  5. #include <stdint.h>


  6. /*

  7. 1、异常复制

  8. 2、异常重抛

  9. */


  10. /////////////////////////////////////////////////////////////////////////////////////////////////


  11. void HandlerException(std::exception_ptr eptr) noexcept {

  12. std::cout << "handler exception" << std::endl;

  13. // 处理失败,重新抛出。

  14. try {

  15. std::rethrow_exception(eptr);

  16. }

  17. catch (const std::exception& e) {

  18. std::cerr << e.what() << '\n';

  19. }

  20. }


  21. void RethrowException() noexcept(false)

  22. {

  23. try {

  24. std::string().at(1);

  25. }

  26. catch (const std::exception& e) {

  27. std::cerr << e.what() << '\n';


  28. auto eptr1 = std::current_exception();

  29. auto eptr2 = std::current_exception();

  30. HandlerException(eptr1);

  31. }


  32. // 当前异常指针对象已经失效,因为之前已经创建过eptr1并且创建后的指针对象已经销毁.

  33. auto eptr = std::current_exception();

  34. if ( eptr == NULL )

  35. std::cout << "eptr is nullptr exception" << std::endl;

  36. }


  37. /////////////////////////////////////////////////////////////////////////////////////////////////

  38. int main(int argc, char const *argv[])

  39. {

  40. std::cout << "----------1、异常复制---------------" << std::endl;

  41. // 1、std::current_exception():返回一个 std::exception_ptr 类型对象,它引用了当前被处理的异常或者说是当前被处理的异常的复制。

  42. // 如果没有异常抛出时,返回的是 null 的 exception_ptr 对象。

  43. // 当异常 exception_ptr 对象失效时,std::current_exception() 就不再返回这个异常

  44. // 2、实际上可以把 std::current exception() 当做返回一个 std::shared ptr 类型的异常对象。只要共享对象计数为0时,异常对象会销毁。


  45. // 获取当前异常, 如果没有异常, 那么返回一个异常对象,但它的内部成员变量为NULL.

  46. auto eptr = std::current_exception();

  47. if ( eptr == NULL )

  48. std::cout << "no exception throw" << std::endl;



  49. system("pause");


  50. std::cout << "----------2、异常重抛---------------" << std::endl;

  51. // 1、捕抓到异常后,如果这个异常处理不了,比如某个条件不能满足不能继续处理下去,那么需要重新抛出异常。

  52. // 让更外层的异常捕抓器处理,那么可以通过以下函数:

  53. // std::rethrow_ exception( exception_ptr p ); // 重新抛出异

  54. RethrowException();

  55. system("pause");


  56. return 0;

  57. }

C++11特性:decltype 类型声明说明符

decltype.cpp

  1. #include <algorithm>

  2. #include <vector>

  3. #include <iostream>

  4. #include <string>

  5. #include <memory>

  6. #include <map>


  7. /*

  8. decltype 语法:

  9. 1、decltype() 说明符在编译时获取()里的声明类型,注意,不是运行时获取类型,特别是多态类型的对象,只能获取该对象当前表示的类型,不能获取实际类型。

  10. 2、decltype 和 auto 不同的是它支持表达式。

  11. decltype 场景:

  12. 1、用在后缀返回语法里,比如模板。

  13. 2、用在获取 lambda表达式的类型。

  14. 3、简化类型声明,经常用在获取auto类型的声明类型,之后声明一个该类型的变量。

  15. */



  16. /////////////////////////////////////////////////////////////////////////////////////////////////////

  17. // 函数相关

  18. template <typename T>

  19. std::string TypeName()

  20. {

  21. std::string r = typeid(T).name();

  22. if (std::is_lvalue_reference<T>::value)

  23. r += "&";

  24. else if (std::is_rvalue_reference<T>::value)

  25. r += "&&";

  26. return r;

  27. }


  28. template <typename T>

  29. void Print()

  30. {

  31. std::cout << "value type is :" << TypeName<T>() << std::endl;

  32. }


  33. // 后缀返回语法

  34. template<class T, class N>

  35. auto AddTemplate(T t, N n)->decltype(t + n) {

  36. return t + n;

  37. }


  38. /////////////////////////////////////////////////////////////////////////////////////////////////////


  39. int main(int argc, char const *argv[])

  40. {

  41. std::cout << "decltype 语法:" << std::endl;

  42. std::cout << "----------1、decltype() 说明符在编译时获取()里的声明类型---------------" << std::endl;

  43. // 注意,不是运行时获取类型,特别是多态类型的对象,只能获取该对象当前表示的类型,不能获取实际类型。

  44. int i = 0;

  45. decltype(i) j; // int

  46. Print<decltype(j)>();


  47. decltype((i)) j1 = j; // 带括号推导出引用类型. int&

  48. Print<decltype(j1)>();


  49. // decltype(int); // 编译错误,不允许使用类型.

  50. system("pause");


  51. std::cout << "----------1、decltype() 说明符在编译时获取()里的声明类型---------------" << std::endl;

  52. // 如果表达式的值类型是 xvalue(过期值,可以理解为编译器生成的临时变量),那么 decltype推导( yields)出T&&

  53. decltype(std::move(i)) a1 = std::move(2); // int&&

  54. Print<decltype(a1)>();

  55. // 如果表达式的值类型是 lvalue(左值),那么 decltype推导( yields)出T&

  56. int m = 2; // 值类型是左值

  57. decltype(m = 3) m2 = m; // 表达式是左值表达式, 那么结果就是左值引用

  58. Print<decltype(m2)>();


  59. struct A

  60. {

  61. double x;

  62. };

  63. const A *a;

  64. decltype(a->x) y; // 值类型是纯右值

  65. Print<decltype(y)>();

  66. decltype(m == 3) m3; // 值类型是纯右值

  67. Print<decltype(m3)>();

  68. system("pause");



  69. std::cout << "decltype 场景:" << std::endl;

  70. std::cout << "---------1、用在后缀返回语法里,比如模板。---------------" << std::endl;

  71. std::cout << "AddT: " << AddTemplate(3.14, 6) << std::endl;

  72. system("pause");


  73. std::cout << "---------2、用在获取 lambda表达式的类型。---------------" << std::endl;

  74. // 在对 map 的 key 进行指定排序以下 map 因为需要指定 map 的比较函数类型,需要在模板特例化知道类型,那么获取 Lambda 表达式类型的唯一方式就是通过 decltype();

  75. // 声明 lambda 表达式的类型,之后应用于模板特例.

  76. auto func = [](int i, int j)->bool { return i > j; };


  77. // 通过 lambda 实现排序功能。

  78. std::map<int, std::string, decltype(func)> prs1(func);

  79. prs1[1] = "1";

  80. prs1[2] = "2";

  81. for (auto &one : prs1)

  82. std::cout << one.first << std::endl;

  83. system("pause");


  84. std::cout << "---------3、简化类型声明,经常用在获取auto类型的声明类型,之后声明一个该类型的变量。---------------" << std::endl;

  85. std::map<int, std::string> prs0;

  86. prs0[1] = "1";

  87. prs0[2] = "2";

  88. for (auto &one : prs0)

  89. std::cout << one.first << std::endl;


  90. auto ite = prs0.begin();

  91. decltype(ite) ite2;

  92. system("pause");


  93. return 0;

  94. }

C++11特性:initializer-list 初始化列表

initializer-list.cpp

  1. #include <iostream>

  2. #include <typeinfo>

  3. #include <vector>

  4. #include <list>

  5. #include <map>

  6. #include <string>

  7. #include <queue>

  8. #include <set>

  9. #include <memory>


  10. /*

  11. 1、C++98 和 C++11 的初始化列表。

  12. 2、{}禁止用高精度赋值给低精度类型的初始化列表。

  13. 3、统一初始化列表的语法和语义。

  14. */


  15. /////////////////////////////////////////////////////////////////////////////////////////////////////


  16. int main(int argc, char const *argv[])

  17. {

  18. std::cout << "----------1、C++98 和 C++11 的初始化列表。---------------" << std::endl;

  19. std::cout << "C++98 的初始化列表'" << std::endl;

  20. // 初始化静态数组可以用初始化列表。

  21. int number1[] = { 1, 2, 3, 4 };

  22. int number2[4] = { 0, 1, 4, 7 };


  23. // 动态数组可以使用() 初始化为0。

  24. int* number3 = new int[5](); // 初始化为0

  25. // STL容器不能使用{}初始化。

  26. // std::vector<int> vector1 = { 1, 2, 3 }; // C++98 编译错误


  27. std::cout << "C++11 的初始化列表'" << std::endl;

  28. // C++11的{}方式初始化列表可以直接对STL容器类型初始化。

  29. std::cout << "std::vector InitializerList" << std::endl;

  30. std::vector<int> vector1 = { 1, 2, 3 }; // C++11 编译通过

  31. for (auto one : vector1)

  32. std::cout << "vector1 one: " << one << std::endl;


  33. std::cout << "std::list InitializerList" << std::endl;

  34. std::list<std::string> list1 = { "hello","vic.MINg" };

  35. for (auto one : list1)

  36. std::cout << "list1 one: " << one << std::endl;


  37. std::cout << "std::set InitializerList" << std::endl;

  38. std::set<float> set1 = { 0.1f, -1.1f, 49.2223f, 90.0f};

  39. for (auto one : set1)

  40. std::cout << "set1 one: " << one << std::endl;


  41. std::cout << "std::queue InitializerList not support" << std::endl; // std::queue 不支持 初始化


  42. std::cout << "std::string InitializerList" << std::endl;

  43. std::string str1 = { 'v','i','c','.','M','I','N','g' };

  44. for (auto one : str1)

  45. std::cout << "str1 one: " << one << std::endl;


  46. std::cout << "std::map InitializerList" << std::endl;

  47. std::map<std::string, std::vector<int>> map1{ { "onetwothree",{ 1,2,3 } },{ "fourfivesix",{ 4,5,6 } } }; // map 是无序的

  48. for (auto one : map1) {

  49. auto& ite = one;

  50. auto& str = ite.first;

  51. auto& array = ite.second;

  52. std::cout << "map1 key: " << str << " size: " << array.size() << std::endl;

  53. }


  54. // 直接访问, std::initializer_list是不可变序列

  55. for (auto one : { 6,7,8 })

  56. std::cout << "one: " << one << std::endl;


  57. auto sil = { 10,11,12 };

  58. for (auto ite = sil.begin(); ite != sil.end(); ++ite)

  59. std::cout << "one: " << *ite << std::endl;

  60. system("pause");


  61. std::cout << "----------2、{}禁止用高精度赋值给低精度类型的初始化列表。---------------" << std::endl;

  62. // int a1[2] = {1, 2.1}; // C++11 double 转 int 会编译错误 C++98 支持的数组初始化

  63. // std::vector<int> v1 = { 1, 2, 3, 4.0 };

  64. system("pause");


  65. std::cout << "----------3、统一初始化列表的语法和语义。---------------" << std::endl;

  66. // C+-11开始可以用进行初始化,包括原始对象和类对象。

  67. class OneClass

  68. {

  69. public:

  70. OneClass(int i) { i_ = i; }

  71. int i_;

  72. };

  73. // 统一初始化语法和语义, 可以用{}来进行到底.

  74. int b1{ 1 }; // 初始化整数,相当于 int b1 = 1;

  75. int b2 = { 2 };

  76. int* pb3 = new int{ 3 };

  77. int b4 = int{ 4 };


  78. OneClass a1{ 1 }; // A a1_1(1);

  79. OneClass a2 = { 2 }; // A a2_1 = 2;

  80. OneClass* pa3 = new OneClass{ 3 }; // A* pa3_1 = new A(3);

  81. OneClass a4 = OneClass{ 4 }; // A a4_1 = A(4);

  82. system("pause");


  83. return 0;

  84. }

C++11特性:inline-namespace 内联命名空间

ming.h

  1. #pragma once


  2. // namespace MINg

  3. namespace MINg

  4. {

  5. #include "version01.hpp"

  6. #include "version02.hpp"

  7. }

version01.hpp

  1. #pragma once


  2. // namespace Version01

  3. namespace Version01

  4. {

  5. void fun(int);

  6. }


  7. #include <iostream>

  8. #include "ming.h"


  9. void MINg::Version01::fun(int i) {

  10. std::cout << "Version01 fun int: " << i << std::endl;

  11. }

version02.hpp

  1. #pragma once


  2. // namespace Version02

  3. inline namespace Version02

  4. {

  5. void fun(int);

  6. void fun(double);

  7. }


  8. #include <iostream>

  9. #include "ming.h"


  10. void MINg::Version02::fun(int i) {

  11. std::cout << "Version02 fun int: " << i << std::endl;

  12. }


  13. void MINg::Version02::fun(double d)

  14. {

  15. std::cout << "Version02 fun double: " << d << std::endl;

  16. }

inline-namespace.cpp

  1. #include <iostream>

  2. #include <string>

  3. #include "../include/ming.h"


  4. /*

  5. 1、语法和说明

  6. 2、常见用法

  7. */


  8. using namespace MINg;


  9. int main(int argc, char const *argv[])

  10. {

  11. std::cout << "----------1、语法和说明---------------" << std::endl;

  12. // 说明:内联命名空间是想要在语言层面提供一种机制,它能让库在版本迭代中支持版本化的表示方法

  13. // 语法:在 namespace 前加 inline 声明的命令空间,它所在的命名空间可以直接访问 inline 命名空间里的声明内容。



  14. std::cout << "----------2、常见用法---------------" << std::endl;

  15. // 声明库时,随着库的演进,给库加上一个版本化的命名空间。

  16. // 研发了一个软件 MINg, 发行 Version 01 版本时,有一个功能 fun(int)

  17. // 发行 Version 02 版本时,fun(int) 进行了功能改进,并且添加了一个功能 fun(double)

  18. Version01::fun(1);

  19. Version02::fun(1);

  20. // 如果不加命名空间,则调用内联命名空间的函数。

  21. fun(2);

  22. fun(3.14);

  23. system("pause");


  24. return 0;

  25. }

C++11特性:lambda 表达式

lambda.cpp

  1. #include <algorithm>

  2. #include <vector>

  3. #include <iostream>

  4. #include <string>

  5. #include <array>

  6. #include <functional>



  7. /*

  8. 1、Lambda表达式的说明语法。

  9. 2、Lambda表达式在STL里的应用。

  10. 3、Lambda表达式在自定义函数里的应用。

  11. */


  12. ///////////////////////////////////////////////////////////////////////////////////////


  13. class SortClass

  14. {

  15. public:


  16. std::vector<int> m_vVector;

  17. std::string m_strName;


  18. SortClass() :m_strName{ "vic.MINg" } {}


  19. template<typename T>

  20. std::vector<int> Filter(T func) {

  21. std::cout << "SortClass::Filter()" << std::endl;

  22. return func(m_vVector);

  23. }


  24. typedef std::vector<int>(*pFilter)(std::vector<int>& input);

  25. std::vector<int> Filter2(pFilter func) {

  26. std::cout << "SortClass::Filter2()" << std::endl;

  27. return func(m_vVector);

  28. }



  29. void Sort() {


  30. std::cout << "SortClass::Sort()" << std::endl;

  31. m_vVector.resize(5);

  32. int index = 0;

  33. int maxIndex = 0xffff;

  34. std::generate(m_vVector.begin(), m_vVector.end(), [&index]() {return ++index; });


  35. // 没有&符号是传值模式, 无法修改.

  36. // 在类里的方法和函数, 如果需要引用 this实例, 那么需要在捕抓列表里添加&或this.

  37. std::sort(m_vVector.begin(), m_vVector.end(), [&, maxIndex](int a, int b) {

  38. // std::cout << "name : " << this->m_strName << std::endl;

  39. // maxIndex = 0; 编译错误 expression must be a modifiable lvalue

  40. return a > b;

  41. });


  42. for (auto one : m_vVector)

  43. std::cout << "SortClass : " << "name = " << this->m_strName << ", one = " << one << std::endl;


  44. // 按照升序排列

  45. // 可以加后缀返回语法,即返回类型->bool

  46. auto funcSortAscend = [](int a, int b)->bool {

  47. return a < b;

  48. };

  49. std::cout << typeid(funcSortAscend).name() << std::endl;


  50. std::sort(m_vVector.begin(), m_vVector.end(), funcSortAscend);

  51. for (auto one : m_vVector)

  52. std::cout << "SortClass : " << "name = " << this->m_strName << ", one = " << one << std::endl;

  53. }

  54. };


  55. /////////////////////////////////////////////////////////////////////////////////////////////////



  56. int main(int argc, char const *argv[])

  57. {

  58. std::cout << "----------1、Lambda表达式的说明语法。---------------" << std::endl;

  59. // 语法:[捕捉列表:可选] (函数参数:可选) [->类型, 返回类型语法:可选] { 函数体 }


  60. int a = 1, b = 2, c = 3;

  61. auto retVal = [=, &a, &b]() mutable->int

  62. {

  63. printf("inner a[%d] b[%d] c[%d]\n", a, b, c);

  64. a = 10;

  65. b = 20;

  66. c = 30;

  67. printf("inner c2[%d]\n", c);

  68. return a + b;

  69. };

  70. printf("sum[%d]\n", retVal());

  71. printf("a[%d] b[%d] c[%d]\n", a, b, c);

  72. system("pause");


  73. std::cout << "----------2、Lambda表达式在STL里的应用。---------------" << std::endl;


  74. class OneClass

  75. {

  76. public:

  77. std::string m_strName;

  78. int m_nID;


  79. OneClass(const std::string name, const int id) : m_strName(name), m_nID(id) {}


  80. static bool cmp(const OneClass a, const OneClass b)

  81. {

  82. return a.m_nID < b.m_nID;

  83. }

  84. };


  85. OneClass OneA("A", 42);

  86. OneClass OneB("B", 23);

  87. OneClass OneC("C", 13);

  88. OneClass OneD("D", 34);

  89. OneClass OneE("E", 7);


  90. std::array<OneClass, 5> classList = { OneA, OneB, OneC, OneD, OneE };

  91. // C++98 排序

  92. std::sort(classList.begin(), classList.end(), OneClass::cmp);

  93. // C++11 Lambda 排序

  94. std::sort( classList.begin(), classList.end(),

  95. [](const OneClass a, const OneClass b) { return a.m_nID < b.m_nID; } );

  96. // C++11 Lambda 遍历

  97. for_each( classList.begin(), classList.end(),

  98. [](const OneClass one) { std::cout << "OneClass : " << "name = " << one.m_strName << ", id = " << one.m_nID << std::endl; });

  99. system("pause");


  100. std::cout << "----------3、Lambda表达式在自定义函数里的应用。---------------" << std::endl;


  101. // 局部类不能使用模板


  102. SortClass sort;

  103. sort.Sort();


  104. // 可以传递lambda函数作为模板特例.

  105. auto numbers = sort.Filter([](std::vector<int>& v1) {

  106. std::vector<int> v2;

  107. for (auto one : v1) {

  108. if (one % 2)

  109. v2.push_back(one);

  110. }

  111. return v2;

  112. });


  113. for (auto one : numbers)

  114. std::cout << "SortClass.Filter() : " << "name = " << sort.m_strName << ", one = " << one << std::endl;


  115. // 可以传递lambda函数作为参数是函数指针的方法。

  116. auto numbers2 = sort.Filter2([](std::vector<int>& v1) {

  117. std::vector<int> v2;

  118. for (auto one : v1) {

  119. if (one % 2)

  120. v2.push_back(one);

  121. }

  122. return v2;

  123. });

  124. for (auto one : numbers2)

  125. std::cout << "SortClass.Filter2() : " << "name = " << sort.m_strName << ", one = " << one << std::endl;


  126. system("pause");


  127. return 0;

  128. }

C++11特性:noexcept 操作法阻止异常传播

noexceρt 是 C++11 是新增的函数修饰符,用来声明该函数不会抛出异常,如果抛出异常,那么异常不会传播,只会直接终止程序。相对的 throw() 这个在函数声明里的修饰符已经失效,它刚好和 noexcept 相反,它声明函数可能会抛出某种异常;还有另一种作用就是 noexcept 被设计比 throw() 更为简单高效的机制。

noexcept.cpp

  1. #include <iostream>

  2. #include <string>

  3. #include <vector>

  4. #include <string.h>

  5. #include <stdint.h>


  6. /*

  7. 1、语法和说明

  8. 2、常用用法

  9. */


  10. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

  11. void Noexcept1()

  12. {

  13. auto str = std::string("abc").substr(10);

  14. }


  15. void Noexcept2() noexcept(false)

  16. {

  17. auto str = std::string("abc").substr(10);

  18. }


  19. void Noexcept3(std::vector<int>& args) noexcept(true)

  20. {

  21. std::cout << "args[1]: " << args[1] << std::endl;

  22. }



  23. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////


  24. int main(int argc, char const *argv[])

  25. {

  26. std::cout << "----------1、语法和说明---------------" << std::endl;

  27. // 语法

  28. // func() noexcept 等价于 func() noexcept(true)

  29. // func() noexcept(expression) expression = true (不会抛出异常) / expression = false (可以抛出异常)

  30. // 说明

  31. // 1、一个析构函数不应该抛出异常;一个自动生成的析构函数会在以下情况满足时隐式声明为 noexcept,就是所有它的类的成员又都 noexcept 的析构函数。

  32. // 一个简单类默认就有 noexcept 析构

  33. // 2、一个生成的复制和移动操作符会在以下情况满足时隐式声明为 noexcept,就是所有在这些操作符里用到的类实例有 noexcept 析构。


  34. system("pause");


  35. std::cout << "----------2、常见用法---------------" << std::endl;

  36. try {

  37. // 不加noexcept时,可以捕抓异常.

  38. Noexcept1();

  39. }

  40. catch (const std::exception& e) {

  41. std::cerr << e.what() << '\n';

  42. }


  43. try {

  44. // noexcept的表达式为false时,可以捕抓异常.

  45. Noexcept2();

  46. }

  47. catch (const std::exception& e) {

  48. std::cerr << e.what() << '\n';

  49. }


  50. std::vector<int> args = { 1,2,3 };

  51. args.clear();

  52. std::cout << "args.capacity(): " << args.capacity() << std::endl;

  53. args.reserve(0); // 内置规则不允许清空小的容量.

  54. std::cout << "args.capacity(): " << args.capacity() << std::endl;


  55. args = std::vector<int>();

  56. auto func = [&args]() {

  57. Noexcept3(args);

  58. };


  59. try {

  60. // noexcept的表达式为里抛出异常时为true, 捕抓异常失败.

  61. func();

  62. }

  63. catch (const std::exception& e) {

  64. std::cerr << e.what() << '\n';

  65. }


  66. system("pause");


  67. return 0;

  68. }

C++11特性:nullptr 空指针常量

nullptr 空指针常量 :是C++11提供的内置空指针类型的常量,它的类型就是 std::nullptr_t 这个类型还是通过以下定义的,所以说它的类型并不是内置的。 

typedefdecltype(nullptr)nullptr_t;

nullptr.cpp

  1. #include <algorithm>

  2. #include <vector>

  3. #include <iostream>

  4. #include <string>

  5. #include <memory>


  6. /*

  7. 1、nullptr 的作用。

  8. 2、nullprt & NULL。

  9. */


  10. /////////////////////////////////////////////////////////////////////////////////////////////////

  11. void Print(int i) {

  12. std::cout << "i: " << i << std::endl;

  13. }


  14. void Print(const char* str) {

  15. std::cout << "str: " << ((str) ? str : "") << std::endl;

  16. }


  17. /////////////////////////////////////////////////////////////////////////////////////////////////


  18. int main(int argc, char const *argv[])

  19. {

  20. std::cout << "----------1、nullptr 的作用---------------" << std::endl;

  21. // nullptr空指针常量就是在重载函数里,传递 nullptr会调用指针参数的函数,而不会调用参数为int类型的函数。

  22. Print(10);

  23. Print("10");

  24. // Print(NULL); // 编译错误, 因为 NULL可以表示整数0,或者指针. 两个重载函数不知道选哪个。

  25. Print(nullptr); // 调用 Print(str); 只有这个作用, 在重载函数里能区分指针调用和整型调用。

  26. system("pause");


  27. std::cout << "----------2、nullprt & NULL。---------------" << std::endl;

  28. // 不允许 nullptr 赋值给整型,NULL可以

  29. //int i = nullptr; // 编译错误, 空指针类型不是int.


  30. // 可以把NULL、0赋值给 std::nullptr_t 类型,其他值不可以

  31. std::nullptr_t nl = NULL;

  32. system("pause");


  33. return 0;

  34. }

C++11特性:rang-for 循环语句

循环语句 for(x:y) 是 C++11 新増的快速枚举的语句,基于范围的for语句( range-for)。使我们能减少代码量,提高开发效率。 

STL库支持的有 

容器类型:vector、set、list、map 

序列类型:string 

判断的依据就是:这个类必须有 begin() 和 end() 方法,返回枚举类型。或者支持标准的 std::begin(x) 和,std::end(x) 返回枚举类型。

rang-for.cpp

  1. #include <algorithm>

  2. #include <vector>

  3. #include <iostream>

  4. #include <map>

  5. #include <time.h>

  6. #include <string>

  7. #include <string.h>

  8. #include <stdint.h>

  9. #include <typeinfo>



  10. /*

  11. 1、C++98 循环语句 和 C++11的 rang-for 对比。

  12. 2、自定义类型支持 rang-for。

  13. */


  14. /////////////////////////////////////////////////////////////////////////////////////////////////////

  15. // 自定义数据类型实现枚举可以使用range-for

  16. // 该类必须有 begin() 和 end() 方法,如果没有该方法,那么需要支持 std::begin(x) 和 std::end(x) 返回枚举类型。

  17. class OneData

  18. {

  19. public:

  20. OneData(std::initializer_list<int> list) {

  21. v2 = list;

  22. }


  23. inline void Add(int a) {

  24. v2.push_back(a);

  25. }


  26. std::vector<int>::iterator begin() {

  27. return v2.begin();

  28. }


  29. std::vector<int>::iterator end() {

  30. return v2.end();

  31. }

  32. private:

  33. std::vector<int> v2;

  34. };

  35. /////////////////////////////////////////////////////////////////////////////////////////////////////



  36. int main(int argc, char const *argv[])

  37. {

  38. std::cout << "----------1、C++98 循环语句 和 C++11的 rang-for 对比。---------------" << std::endl;

  39. std::cout << "C++98 循环语句'" << std::endl;

  40. std::vector<char> v1 = { 'a','b','c','d' };

  41. // for 循环

  42. for (size_t i = 0; i < v1.size(); i++) {

  43. std::cout << "i-> " << i << ": value-> " << v1[i] << std::endl;

  44. }

  45. // while 循环

  46. size_t index = 0;

  47. while (index < v1.size()) {

  48. std::cout << "index-> " << index << ": value-> " << v1[index] << std::endl;

  49. ++index;

  50. }

  51. // std::for_each 循环

  52. std::for_each(v1.begin(), v1.end(), [](char one) {

  53. std::cout << "value-> " << one << std::endl;

  54. });


  55. std::cout << "C++11的 rang-for'" << std::endl;

  56. // 通过 range-for 修改值后打印

  57. for (auto& one : v1) {

  58. one = rand() % 26 + 'a';

  59. }

  60. for (auto one : v1) {

  61. std::cout << "value-> " << one << std::endl;

  62. }

  63. system("pause");


  64. std::cout << "----------2、自定义类型支持 rang-for。---------------" << std::endl;

  65. OneData data{ 5, 6, 7 };

  66. for (auto one : data) {

  67. std::cout << "value-> " << one << std::endl;

  68. }

  69. system("pause");



  70. return 0;

  71. }

C++11特性:rvalue-reference 右值引用和移动语义

rvalue-reference.cpp

  1. #include <algorithm>

  2. #include <vector>

  3. #include <iostream>

  4. #include <string>

  5. #include <stdlib.h>

  6. #include <memory>


  7. /*

  8. 1、右值引用的定义

  9. 2、移动语义,和右值的关系

  10. 3、常见用法

  11. */


  12. //////////////////////////////////////////////////////////////////////////////////////////////////////////////


  13. void Print(const char* str, const char* title = "str") {

  14. std::cout << title << ": " << ((str) ? str : "") << std::endl;

  15. }



  16. template<class T>

  17. void swap(T& a, T& b) // "perfect swap" (almost)

  18. {

  19. T tmp = move(a); // could invalidate a

  20. a = move(b); // could invalidate b

  21. b = move(tmp); // could invalidate tmp

  22. }



  23. template <typename T>

  24. void func(T t) {

  25. std::cout << "in func" << std::endl;

  26. }


  27. template <typename T>

  28. void relay(T&& t) {

  29. std::cout << "in relay" << std::endl;


  30. // std::forward() 完美转发:实现了参数在传递过程中保持其值属性的功能,即若是左值,则传递之后仍然是左值,若是右值,则传递之后仍然是右值。

  31. func(std::forward<T>(t));

  32. }


  33. //////////////////////////////////////////////////////////////////////////////////////////////////////////////


  34. int main(int argc, char const *argv[])

  35. {

  36. std::cout << "----------1、右值引用的定义---------------" << std::endl;

  37. // 右值引用:T&& 左值引用:T&

  38. // 非常量的右值,通常说的是编译器生成的临时对象。

  39. // 右值引用声明可以区别一个左值和右值

  40. // 右值引用通过移动语义(std::move)产生,它可以把临时对象(一般不能引用)的资源移动到其他地方去。

  41. // 右值引用也可以用来扩展临时对象的生命周期。


  42. int&& i = std::move(1); // rvalue

  43. std::string str1 = "vic.MINg";

  44. std::string str2(std::move(str1));


  45. Print(str2.c_str(), "str2"); // 输出 vic.MINg

  46. Print(str1.c_str(), "str1"); // 输出空,已经被移动到str2里.


  47. std::vector<std::string> vecs;

  48. vecs.push_back(std::move(str2)); // 把 str2 里的资源再次移动到 vector 里, str2 为空

  49. system("pause");


  50. std::cout << "----------2、移动语义,和右值的关系---------------" << std::endl;

  51. // 移动语义在swap里的应用;没有复制数据,只是数据在对象里传递. 减少了数据的构造过程

  52. std::string first("first");

  53. std::string second("second");

  54. std::cout << "first data address: " << (int*)first.data() << std::endl;

  55. std::cout << "second data address: " << (int*)second.data() << std::endl;

  56. swap(first, second);

  57. Print(first.c_str(), "first");

  58. Print(second.c_str(), "second");

  59. std::cout << "first data address: " << (int*)first.data() << std::endl;

  60. std::cout << "second data address: " << (int*)second.data() << std::endl;

  61. system("pause");


  62. std::cout << "----------3、常见用法---------------" << std::endl;

  63. // std::forward() 的使用

  64. // 一个左值和右值的测试类。

  65. class OneClass {

  66. public:

  67. OneClass(){

  68. std::cout << "default constructor" << std::endl;

  69. }

  70. OneClass(const OneClass & t) {

  71. std::cout << "lvalue constructor" << std::endl;

  72. }

  73. OneClass(OneClass && t) {

  74. std::cout << "rvalue constructor" << std::endl;

  75. }

  76. ~OneClass() {

  77. std::cout << "destructor" << std::endl;

  78. }

  79. };


  80. // 右值

  81. relay(OneClass());

  82. // 左值

  83. OneClass oneClass;

  84. relay(oneClass);


  85. system("pause");


  86. return 0;

  87. }

C++11特性:user-defined-literals 用户定义的字面常量

user-defined-literals.cpp

  1. #include <iostream>

  2. #include <string>

  3. #include <string.h>

  4. #include <stdint.h>


  5. /*

  6. 1、语法和说明

  7. 2、常见用法

  8. 3、注意事项

  9. */


  10. /////////////////////////////////////////////////////////////////////////////////////////////////


  11. long double operator"" _mm(long double x) { return x / 1000; }

  12. long double operator"" _m(long double x) { return x; }

  13. long double operator"" _km(long double x) { return x * 1000; }



  14. size_t operator"" _len(char const * str, size_t size)

  15. {

  16. return size;

  17. }

  18. namespace CPP11

  19. {

  20. struct RGBA

  21. {

  22. uint8_t r, g, b, a;

  23. RGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) :r(r), g(g), b(b), a(a) {}

  24. };


  25. RGBA operator"" _RGBA(const char* str, size_t size)

  26. {

  27. const char* r = nullptr, *g = nullptr, *b = nullptr, *a = nullptr;

  28. for (const char* p = str; p != str + size; ++p)

  29. {

  30. if (*p == 'r') r = p + 1;

  31. if (*p == 'g') g = p + 1;

  32. if (*p == 'b') b = p + 1;

  33. if (*p == 'a') a = p + 1;

  34. }

  35. if (r == nullptr || g == nullptr || b == nullptr) throw;

  36. if (a == nullptr)

  37. {

  38. return RGBA(atoi(r), atoi(g), atoi(b), 0);

  39. }

  40. else

  41. {

  42. return RGBA(atoi(r), atoi(g), atoi(b), atoi(a));

  43. }

  44. }

  45. namespace MINg

  46. {

  47. //输出运算符重载

  48. std::ostream& operator<<(std::ostream& os, const RGBA& color)

  49. {

  50. return os << "r=" << (int)color.r << " g=" << (int)color.g << " b=" << (int)color.b << " a=" << (int)color.a << std::endl;

  51. }

  52. }

  53. }



  54. /////////////////////////////////////////////////////////////////////////////////////////////////

  55. int main(int argc, char const *argv[])

  56. {

  57. std::cout << "----------1、语法和说明---------------" << std::endl;

  58. // C++提供了一些字面常量用于内置类型。

  59. auto l_0 = 1ULL; // unsigned long long

  60. auto l_1 = 1L; // long

  61. auto l_2 = 2LL; // long long


  62. auto i_1 = 123; // int

  63. auto i_2 = 123u; // unsigned int

  64. auto od = 0xD0; // 十六进制表示的int

  65. auto b1 = 0b101010; // 二进制表示的int

  66. constexpr auto e1 = 010; // 八进制表示的int


  67. auto d_1 = 1.2; // double

  68. auto f_1 = 1.2f; // float


  69. auto c_1 = 'a'; // char

  70. auto s_1 = "abc"; // const char*


  71. int32_t i32 = 2323; // 常用的整型声明.


  72. // C++11新标准中引入了用户自定义字面量,也叫自定义后缀操作符,即通过实现一个后缀操作符,将申明了该后缀标识的字面量转化为需要的类型。

  73. std::cout << "1.0_mm = " << 1.0_mm << std::endl; // 0.001

  74. std::cout << "1.0_m = " << 1.0_m << std::endl; // 1

  75. std::cout << "1.0_km = " << 1.0_km << std::endl; // 1000

  76. system("pause");


  77. std::cout << "----------2、常见用法---------------" << std::endl;

  78. std::cout << "\"vic.MINg\"_len = " << "vic.MINg"_len << std::endl; //结果为4

  79. system("pause");


  80. std::cout << "----------3、注意事项---------------" << std::endl;

  81. // 因为用户定义的字面常量定义多了有可能混淆和冲突,所以我们最好把它声明在某个命名空间里。

  82. //自定义字面量来表示RGBA对象

  83. using namespace CPP11;

  84. using namespace CPP11::MINg;

  85. std::cout << "r255 g255 b255 a40"_RGBA << std::endl;

  86. system("pause");


  87. return 0;

  88. }

文章转载自林元皓,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论