广州建设监理协会网站,乐陵人力资源中心,做外贸soho要做网站吗,怎样重新运行wordpress前言#xff1a;本篇文章将分享一些C11版本所产生的一些新的技术以及对老版本的优化。 目录
一.C11简介
二.统一的列表初始化
1.{}初始化
2.std::initializer_list
三.右值引用和移动语义
1.左值引用和右值引用 2.两者的比较
#xff08;1#xff09;左值引用 #…前言本篇文章将分享一些C11版本所产生的一些新的技术以及对老版本的优化。 目录
一.C11简介
二.统一的列表初始化
1.{}初始化
2.std::initializer_list
三.右值引用和移动语义
1.左值引用和右值引用 2.两者的比较
1左值引用 2右值引用
3.移动语义
4.万能引用
四.lambda表达式
1.基础使用
2.捕捉列表
五.可变模板参数
六.function包装器 一.C11简介
C11是C委员会自C03起经历了近10年的时间所进行的又一次更新。相比于C98/03C11带来了数量可观的变化其中包含了约140个新特性以及对C03标准中约600个缺陷的修正这使得C11更像是从C98/03中孕育出的一种新语言。
相比较而言C11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全不仅功能更强大而且能提升程序员的开发效率公司实际项目开发中也用得比较多所以我们要作为一个重点去学习。
本文主要分享一些实际中比较实用的语法。 二.统一的列表初始化
1.{}初始化
在C98中标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如
struct Point
{int _x;int _y;
};
int main()
{Point p { 1, 2 };return 0;
} C11扩大了用花括号括起的列表(初始化列表)的使用范围使其可用于所有的内置类型和用户自定义的类型使用初始化列表时可添加等号()也可不添加
class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2022, 1, 1); // old style// C11支持的列表初始化这里会调用构造函数初始化Date d2{ 2022, 1, 2 };Date d3 { 2022, 1, 3 };return 0;
} 2.std::initializer_list
std::initializer_list一般是作为构造函数的参数C11对STL中的不少容器就增加std::initializer_list作为参数的构造函数这样初始化容器对象就更方便了。也可以作为operator的参数这样就可以用大括号赋值
vector(initializer_listT l)
{resize(l.size());for (auto e : l){push_back(e);}
} initializer_list包含两个指针一个指向常量数组的开始一个指向常量数组的结尾的下一个位置。
构造函数的本质就是遍历l将其数据一个一个尾插进容器。
int main()
{vectorint v { 1,2,3,4 };// 这里{sort, 排序}会先初始化构造一个pair对象mapstring, string dict { {sort, 排序}, {insert, 插入} };// 使用大括号对容器赋值v {10, 20, 30};return 0;
} 三.右值引用和移动语义
1.左值引用和右值引用 左值是一个表示数据的表达式(如变量名或解引用的指针)我们可以获取它的地址可以对它赋值左值可以出现赋值符号的左边也可以出现在赋值符号的右边。定义时const修饰符后的左值不能给他赋值但是可以取它的地址。左值引用就是给左值的引用给左值取别名。 // 以下的p、b、c都是左值 int* p new int(0); int b 1; const int c 2; 右值也是一个表示数据的表达式如字面常量、表达式返回值函数返回值(这个不能是左值引用返回)等等右值可以出现在赋值符号的右边但是不能出现出现在赋值符号的左边右值不能取地址。右值引用就是对右值的引用给右值取别名。 // 以下几个都是常见的右值 10; x y; fmin(x, y); 对左值引用我们使用单符号 // 以下几个是对上面左值的左值引用 int* rp p; int rb b; const int rc c; int pvalue *p; 而对右值引用我们则需使用双符号 // 以下几个都是对右值的右值引用 int rr1 10; double rr2 x y; double rr3 fmin(x, y) 2.两者的比较
1左值引用
左值引用只能引用左值不能引用右值。但是const左值引用既可引用左值也可引用右值。左值引用是给原值另起一个别名两者共用一个地址。 int main() { // 左值引用只能引用左值不能引用右值。 int a 10; int ra1 a; // ra为a的别名 //int ra2 10; // 编译失败因为10是右值 // const左值引用既可引用左值也可引用右值。 const int ra3 10; const int ra4 a; return 0; } 2右值引用
右值引用只能右值不能引用左值。但是右值引用可以move以后的左值。右值引用本身是左值。右值引用是直接抢夺资源。 int main() { // 右值引用只能右值不能引用左值。 int r1 10; // error : “初始化”: 无法从“int”转换为“int ” // message : 无法将左值绑定到右值引用 int a 10; int r2 a; // 右值引用可以引用move以后的左值 int r3 std::move(a);//move后边会分享 return 0; } 如上例 r3右值引用a之后r3得到a的数据和地址而a本身则不再具有资源和地址。 3.移动语义
在我们之前所分享的各种容器中都拥有构造函数和赋值函数在C11之前这两个函数都是通过左值引用来作为参数但是C11之后我们可以用右值引用作为参数而两种函数名也变为移动构造和移动赋值
// 移动构造string(string s):_str(nullptr),_size(0),_capacity(0){cout string(string s) -- 移动语义 endl;swap(s);}// 移动赋值string operator(string s){cout string operator(string s) -- 移动语义 endl; swap(s);return *this;}
移动构造和移动赋值相较于传统的构造函数和赋值函数因为右值引用可以直接夺舍资源所以就避免了需要创建一个新的对象来进行资源交换这些繁琐的过程大大提高了效率。 4.万能引用 templatetypename T void fun(T t) {} 函数模版里的右值引用称为万能引用可以传左值右值const左值及const右值均会自动识别。
但是这里存在一个问题因为右值引用本身再下一次传递时会被识别为左值所以我们需要添加东西来保持右值的本身属性而执行该步骤的是完美转发 std::forwardT(参数t) 完美转发可以保证在传参过程中参数会保持其原生类型属性。 四.lambda表达式
1.基础使用
在C11到来之前我们想对一个数据集合进行排序可以通过使用sort函数而遇到自定义类型的数据时如果想要进行排序我们分享过使用仿函数来进行排序。
但是仿函数的写法未免有些复杂和繁琐所以C11中就增加了对自定义类型的数据进行排序的lambda表达式其本质为匿名函数对象。
其结构为 [捕捉列表] (参数) mutable - 返回值类型 { 函数体 } 默认情况下lambda表达式具有常性如果要取消其常性则需添加上述表达式的mutable。
当我们仅使用该表达式可以省略捕捉列表和返回值类型。该表达式的返回值可以使用auto类型的数据进行接收 auto fun1 [](int a,int b)-{return a b;}; auto fun1 [](int a,int b){return a b;}; 上述表达式中的-也是可以省略的。 2.捕捉列表 int a 1,b 2; auto swap [a,b]() {} 捕捉常量可以使lambda表达式捕捉到ab的一份拷贝但是默认为const类型无法对其进行交换如果需要则需添加multable取消其常性。
但是就算添加了multable可以进行交换但依然只是交换了拷贝并不影响ab本身。如果想要交换ab本身就需要传引用 int a 1,b 2; auto swap [a,b]() {} 此种捕捉方式只能是我们传什么就捕捉什么。除此之外我们还可以一次性捕捉父作用域中的全部对象 int a 1,b 2,c 3,d 4, e 5; auto swap []() {} 传“”可以一次性捕捉所有对象而传“”则是一次性捕捉所有引用 int a 1,b 2,c 3,d 4, e 5; auto swap []() {} 另外我们还可以混合捕捉 int a 1,b 2,c 3,d 4, e 5; auto swap [a,b,c,e]() {} 五.可变模板参数
前边我们分享过什么是可变参数即函数的参数数量并不固定可以随心所欲的添加参数例如最常用的scanf和printf两个函数。在C11中大佬们为模版也设计了可变参数具体结构如下 // Args是一个模板参数包args是一个函数形参参数包 // 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。 template class ...Args void ShowList(Args... args) {} 上面的参数args前面有省略号所以它就是一个可变模版参数我们把带省略号的参数称为“参数包”它里面包含了0到NN0个模版参数。 六.function包装器
包装器function是一种类模板使用包装器需要添加头文件includefunctional其结构为 function返回值类型(参数类型...) 包装器名字 包装器可以使用的场景针对于可调用对象包括函数指针函数对象lambda表达式以及类的成员函数。
所谓包装器就是给上述举例的这些包装一个相同的外壳使它们调用起来更加方便统一
#include functional
int f(int a, int b)
{return a b;
}
struct Functor
{
public:int operator() (int a, int b){return a b;}
};
class Plus
{
public:static int plusi(int a, int b){return a b;}double plusd(double a, double b){return a b;}
};
int main()
{// 函数名(函数指针)std::functionint(int, int) func1 f;cout func1(1, 2) endl;// 函数对象std::functionint(int, int) func2 Functor();cout func2(1, 2) endl;// lamber表达式std::functionint(int, int) func3 [](const int a, const int b) {return a b; };cout func3(1, 2) endl;// 类的成员函数std::functionint(int, int) func4 Plus::plusi;cout func4(1, 2) endl;std::functiondouble(Plus, double, double) func5 Plus::plusd;cout func5(Plus(), 1.1, 2.2) endl;return 0;
} 结语
关于C11就分享这么多喜欢本篇文章记得一键三连我们下期再见