C++11(下篇)

news/2024/5/21 8:51:19

文章目录

  • C++11
    • 1. 模版的可变参数
      • 1.1 模版参数包的使用
    • 2. lambda表达式
      • 2.1 Lambda表达式语法
        • 捕获列表说明
      • 2.2 lambda的底层
    • 3. 包装器
      • 3.1 function包装器
      • 3.2 bind
    • 4. 线程库
      • 4.1 thread类
      • 4.2 mutex类
      • 4.3 atomic类
      • 4.4 condition_variable类


C++11

1. 模版的可变参数

C++11支持模版的可变参数,可变模版参数比较抽象晦涩,我们只探讨其中基础。

template <class ...Args> // 模版参数包
void ShowList(Args... args) // 函数参数包
{}

...表明是可变模版参数,称为参数包,可以有 [ 0 , N ] [0,N] [0,N] 个模版参数。可变参数的模版函数,同样是根据调用情况,实例化出多份。

// 展示参数包个数
cout << sizeof...(Args) << endl;
cout << sizeof...(args) << endl;

1.1 模版参数包的使用

void showlist()
{cout << endl;
}template<class T, class... Args>
void show_list(const T& val, Args... args)
{cout << val << " "; // 使用第一个参数showlist(args...); // 向下递归传递参数包
}int main()
{showlist();showlist('1');showlist('1', 2);showlist('1', 2, "string");return 0;
}

参数包可以递归解析。

  1. 首先无参调用可直接调用无参版本。
  2. 其次有参调用的第一个参数会被val获取,之后的参数会被参数包获取。
  3. 使用完第一个参数后,可以传参数包下去递归调用。

打印剩余的参数:

void showlist()
{cout << endl;
}template<class T, class...Args>
void showlist (const T& val, Args... args)
{cout << __FUNCTION__ <<"-->" << sizeof...(args)<<endl;//cout << val << " ";showlist(args...);//cout << sizeof...(args) << endl;//计算大小//如何解析出可变参数包呢?//不能这么玩,语法不支持//for (int i = 0; i < sizeof...(args); i++)//{//	cout << args[i] << " ";//}
}int main()
{showlist('x', 1,2,"string");return 0;
}

在这里插入图片描述

线程库就是使用可变模版参数,支持传递任意个参数。 

2. lambda表达式

2.1 Lambda表达式语法

[capture-list](parameters) mutable -> return-type { statement }
语法组成解释是否省略
[capture_list]捕获列表,捕捉当前作用域中的变量。分为传值捕捉和引用捕捉不可省略
(param_list)参数列表,形参默认具有const属性,可加mutable去除常属性可省略
-> ret_type指明返回类型可省略自动推导
{}函数体内容不可省略

各部分说明:

  1. capture-list: 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据来。判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。
  2. (parameters): 参数列表与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略。
  3. mutable: 默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
  4. -> return-type: 返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回0值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导
  5. { statement }: 函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

注意:

在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:0;该lambda函数不能做任何事情。

看个样例代码:

int main()
{// 最简单的lambda表达式, 该lambda表达式没有任何意义[]{}; // 省略参数列表和返回值类型,返回值类型由编译器推导为intint a = 3, b = 4;[=]{return a + 3; }; // 省略了返回值类型,无返回值类型auto fun1 = [&](int c){b = a + c; }; fun1(10);cout<<a<<" "<<b<<endl;// 各部分都很完善的lambda函数auto fun2 = [=, &b](int c)->int{return b += a+ c; }; cout<<fun2(10)<<endl;// 复制捕捉xint x = 10;auto add_x = [x](int a) mutable { x *= 2; return a + x; }; cout << add_x(10) << endl; return 0;
}

通过上述例子可以看出,lambda表达式实际上可以理解为无名函数,该函数无法直接调 用,如果想要直接调用,可借助auto将其赋值给一个变量。

捕获列表说明

[captrue_list] 捕获列表,用来捕捉当前作用域前和全局的变量。[]不可省略。

  • 分为传值捕捉和引用捕捉,引用捕捉[&a, &b]
  • [&]表示全引用捕捉,[=]表示全传值捕捉。捕捉所有能捕捉的变量。
  • [&a, =]表示混合捕捉,引用捕捉a变量,其他变量传值捕捉。但不可重复捕捉。
  • 捕捉列表和参数列表的变量默认用const修饰,可加mutable解除修饰
auto func1 = [a, b] () {};   // 传值捕捉
auto func2 = [&a, &b] () {}; // 引用捕捉
auto func3 = [=] () {}; // 全传值捕捉
auto func4 = [&] () {}; // 全引用捕捉// 混合捕捉
[&a, &b, =](){}; // 引用捕捉a和b变量,其他变量传值捕捉
[=, a](){}; // 重复传值捕捉a,编译报错

注意

  • 父作用域指包含lambda函数的语句块

  • 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。

​ 比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量

//Lambda表达式捕捉列表的示例
auto lambda1 = [=, &b]() {std::cout << "Inside lambda1: a = " << a << ", b = " << b << std::endl;// 可以访问变量a的值,但只能以值传递的方式访问,而变量b可以以引用传递的方式访问
};
  • 捕捉列表不允许变量重复传递,否则就会导致编译错误。

​ 比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复

//Lambda表达式捕捉列表中不允许变量重复传递的示例
/// 以下代码将导致编译错误,因为变量a已经在捕捉列表中以值传递的方式捕捉了
// auto lambda2 = [=, a]() {}; // 编译错误:重复的捕捉变量'a'
// auto lambda3 = [=, &]() {}; //编译错误:传值和引用不可以同时存在
  • 在块作用域以外的lambda函数捕捉列表必须为空。

    // 在块作用域以外的lambda函数捕捉列表必须为空的示例
    int c = 20;
    auto lambda3 = [=]() {
    // 在此lambda函数中只能访问到变量a和b,无法访问外部的变量cstd::cout << "Inside lambda3: a = " << a << ", b = " << b << std::endl;
    };
    
  • lambda表达式之间不能相互赋值,即使看起来类型相同

    // lambda表达式之间不能相互赋值的示例   
    // auto lambda4 = lambda3; 
    // 编译错误:无法从lambda函数'lambda3'初始化lambda函数'lambda4'
    

2.2 lambda的底层

lambda表达式不能相互赋值,即使看起来类型相同。

auto lamdba = []() {};
cout << sizeof(lamdba) << endl;        // 1
cout << typeid(lamdba).name() << endl; // class `int __cdecl main(void)'::`2'::<lambda_1>// class <lambda_fcbffd5ae4b5ac20353abe92769a204f>

lambda表达式最后会被编译器处理成仿函数,所以lambda是个空类,大小为1。类名不同编译器实现不同,但能保证每个lambda表达式类名不同。

看看仿函数和lambda表达式的底层:

在这里插入图片描述

 

3. 包装器

包装器用来包装具有相同特征用途的多个可调用对象,便于以统一的形式调用它们。

3.1 function包装器

function包装器也叫做适配器,C++中的function本质是一个类模版。定义如下:

#include <functional>template <class RetType, class... ArgsType> /* 声明返回类型和参数类型 */class function<Ret(Args...)>; 
// 普通函数
int func(int a, int b) { return a + b; }	
// 仿函数
struct functor {int operator()(int x, int y) { return x + y; }
};
// 非静态成员函数
struct Plus {int plus(int a, int b) { return a + b; }
};
// 静态成员函数
struct Sub {static int sub(int a, int b) { return a - b; }
};std::function<int(int, int)>          f1 = f;
std::function<int(int, int)>          f2 = Functor();
std::function<int(Plus&, int, int)>   f3 = &Plus::plus;
std::function<int(int, int)>          f4 = Sub::sub;

封装成员函数时需要注意的点有:指定类域、对象参数、加取地址符。

struct Plus {Plus(int i) {}int plus(int a, int b) { return a + b; }
};int main()
{function<int(Plus, int, int)> f1 = &Plus::plus;f1(Plus(1), 1, 2);function<int(Plus&, int, int)> f2 = &Plus::plus;Plus p(1);f2(p, 1, 2);function<int(Plus*, int, int)> f3 = &Plus::plus;f3(&p, 1, 2);function<int(Plus&&, int, int)> f4 = &Plus::plus;f4(Plus(3), 1, 2);return 0;
}

3.2 bind

bind函数也是一个函数包装器,本质是一个函数模版。生成一个新的可调用对象,来调整一个可调用对象的参数列表。

// without return 
template <class Func, class... Args>bind(Func&& fn, Args&&... args);// with return type
template <class Ret, class Func, class... Args>  bind(Func&& fn, Args&&... args);
class suber
{
public:suber(int rt) : _rt(rt){}int sub(int a, int b) { return (a - b) * _rt; }
private:int _rt;
};// 通过bind调整参数顺序
function<int(int, int)> f1 = bind(suber, placeholders::_1, placeholders::_2);
function<int(int, int)> f2 = bind(suber, placeholders::_2, placeholders::_1);
cout << f1(2, 1) << endl;
cout << f2(1, 2) << endl;// 通过bind调整参数个数
function<int(suber, int, int)> f3 = &Sub::sub;
function<int(int, int)> f4 = bind(&Sub::sub, Sub(3), placeholders::_1, placeholders::_2);
cout << f3(Sub(1), 2, 1) << endl;
cout << f4(2, 1) << endl;

 

4. 线程库

C++11提供了跨平台的具有面向对象特性的线程库,线程相关的系统知识在此不作赘述,直接讨论线程库的使用。

4.1 thread类

构造函数解释
thread() noexcept创建thread对象,不执行任何操作
thread(Fn&& fn, Args&&... args)传入调用对象和参数列表
thread(const thread&) = delete线程对象不可拷贝
thread(thread&& th)线程对象支持移动
成员函数解释
void join()等待线程
void detach()分离线程

关于当前线程的一些操作被放到this_thread类中:

this_thread 成员函数解释
thread::id get_id () noexcept返回线程ID
void sleep_for (const chrono::duration<Rep,Period>& rel_time)设置休眠时间
vector<thread> thds(N); // 线程池
atomic<int> x = 0;for (auto& td : thds) {td = thread([&x, M](int i = 0) { while (i++ < M) {cout << this_thread::get_id() << "->" << x << endl; // get_id()this_thread::sleep_for(std::chrono::seconds(1));    // sleep_for()x++;}});
}for (auto& td : thds) {td.join();
}

4.2 mutex类

mutex类封装系统中的互斥锁,具体接口如下:

mutex解释
mutex() noexcept创建互斥锁
mutex (const mutex&) = delete禁止拷贝锁
void lock()加锁
void unlock()解锁
lock_guard解释
explicit lock_guard (mutex_type& m)构造函数
lock_guard (const lock_guard&) = delete不支持拷贝
unique_lock解释
explicit unique_lock (mutex_type& m)构造函数
unique_lock (const unique_lock&) = delete不支持拷贝
void lock()加锁
void unlock()解锁

捕获异常并解锁释放资源是不够友好的,因此异常时资源的处理,交给RAII解决。RAII即资源获取就是初始化,是一种管理资源的用法。

本质是将资源封装成类,自动调用构造和析构。以达到资源获取自动初始化,出作用域自动释放的效果

利用 RAII 封装的成“智能锁”,我们称之为锁守卫lock_guard

4.3 atomic类

保证自增减的原子性,可以使用原子操作。atomic类封装系统原子操作,具体接口如下:

template <class T> struct atomic;T fetch_add (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; // +=
T fetch_sub (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; // -=
T fetch_and (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; // &=
T fetch_or  (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; // |=
T fetch_xor (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; // ^=
T operator++() volatile noexcept; // ++
T operator--() volatile noexcept; // --

无锁算法CAS

Linux原子操作系统调用

4.4 condition_variable类

条件变量是线程同步的一种机制,主要包括两个动作:等待条件变量挂起,条件变量成立运行。

condition_variable解释
condition_variable()构造条件变量
condition_variable (const condition_variable&) = delete禁止拷贝条件变量
void wait (unique_lock<mutex>& lck)直接等待
void wait (unique_lock<mutex>& lck, Predicate pred)指定条件下等待
void notify_one() noexcept唤醒单个线程
void notify_all() noexcept唤醒多个线程
// wait的实现
template <class Predicate>  
void wait (unique_lock<mutex>& lck, Predicate pred)
{while (!pred()) /* pred()为假,进入等待 */wait(lck);
}

tex>& lck) | 直接等待 | |void wait (unique_lock& lck, Predicate pred) | 指定条件下等待 | |void notify_one() noexcept | 唤醒单个线程 | |void notify_all() noexcept` | 唤醒多个线程 |

// wait的实现
template <class Predicate>  
void wait (unique_lock<mutex>& lck, Predicate pred)
{while (!pred()) /* pred()为假,进入等待 */wait(lck);
}

模版参数pred是个可调用对象,其返回值代表线程是否进入临界区的条件。条件为真停止等待,条件为假进入等待。


http://www.mrgr.cn/p/36824570

相关文章

steam怎么退款?steam退款教程?简单几步即可轻松实现退款

steam怎么退款&#xff1f;steam退款教程&#xff1f;简单几步即可轻松实现退款 说到steam平台大家肯定不会陌生&#xff0c;随着现代的发展&#xff0c;在steam上进行购买游戏已经成了很普遍的东西&#xff0c;但是许多玩家在购买游戏试完之后发现游戏并不符合自己的胃口&…

【k8s】:深入理解 Kubernetes 中的污点(Taints)与容忍度(Tolerations)

【k8s】&#xff1a;深入理解 Kubernetes 中的污点&#xff08;Taints&#xff09;与容忍度&#xff08;Tolerations&#xff09; 1、污点&#xff08;Taints&#xff09;2、容忍度&#xff08;Tolerations&#xff09;3、示例演示-测试污点的具体应用场景3.1 给节点打污点&…

微服务之Consul 注册中心介绍以及搭建

一、微服务概述 1.1单体架构 单体架构&#xff08;monolithic structure&#xff09;&#xff1a;顾名思义&#xff0c;整个项目中所有功能模块都在一个工程中开发&#xff1b;项目部署时需要对所有模块一起编译、打包&#xff1b;项目的架构设计、开发模式都非常简单。 当项…

SSL证书添加与ICP备案,对于SpringBoot的要求

配置了SSL证书之后&#xff0c;在SpringBoot的resources文件夹里的application.properties会添加以下代码&#xff1a; server.port443 不需要添加server.address。不然会报错。 https类型的请求默认在Postman里面不可请求。 经过SSL证书处理的网页&#xff0c;链接中使默认…

Python单元测试pytest捕获日志输出

使用pytest进行单元测试时&#xff0c;遇到了需要测试日志输出的情况&#xff0c;查看了文档 https://docs.pytest.org/en/latest/how-to/capture-stdout-stderr.html https://docs.pytest.org/en/latest/how-to/logging.html 然后试了一下&#xff0c;捕捉logger.info可以用…

《Kubernetes部署篇:基于Kylin V10+ARM架构CPU使用containerd部署K8S 1.26.15集群(一主多从)》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:企业级K8s集群运维实战 1、在当前实验环境中安装K8S1.25.14版本,出现了一个问题,就是在pod中访问百度网站,大概时间有10s多,这个时间太长了,尝试了各种办法,都解决不了,后面尝试安装了了1.26.…

OpenAI现已普遍提供带有视觉应用程序接口的GPT-4 Turbo

OpenAI宣布&#xff0c;其功能强大的GPT-4 Turbo with Vision模型现已通过公司的API全面推出&#xff0c;为企业和开发人员将高级语言和视觉功能集成到其应用程序中开辟了新的机会。 PS&#xff1a;使用Wildcard享受不受网络限制的API调用&#xff0c;详情查看教程 继去年 9 月…

2024 抖音欢笑中国年(三):编辑器技巧与实践

前言 本次春节活动中&#xff0c;我们大部分场景使用内部的 SAR Creator互动方案来实现。 SAR Creator 是一款基于 TypeScript 的高性能、轻量化的互动解决方案&#xff0c;目前支持了Web和字节内部跨端框架平台&#xff0c;服务于字节内部的各种互动业务&#xff0c;包括但不限…

【Qt 学习笔记】Qt常用控件 | 按钮类控件Check Box的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 按钮类控件Check Box的使用及说明 文章编号&#xff1a;…

Linux的重要命令(二)+了解Linux目录结构

目录 一.Linux的目录结构 二.查看文件内容命令 1.cat 命令 2.more 命令 3.less 命令 4.head 命令 5.tail 命令 6.拓展 head 和 tail 的其他用法 ​编辑 三.统计文件内容的命令-wc ​编辑 四.检索和过滤文件内容的命令-grep ​编辑 ​编辑 五.压缩命令 gzip 和 bz…

死磕GMSSL通信-java/Netty系列(二)

死磕GMSSL通信-java/Netty系列(二) 在上一篇文章中,我们探讨了如何利用C/C++实现国密通信。而本文将聚焦于Java环境下,特别是基于Netty框架,如何实现与国密系统的安全通信。为了确保新项目遵循最新的国密标准,我们将优先推荐使用GB/T 38636-2020(TLCP)协议。对于Java开…

Yolo-world+Python-OpenCV之摄像头视频实时目标检测

上一次介绍了如何使用最基本的 Yolo-word来做检测&#xff0c;现在我们在加opencv来做个实时检测的例子 基本思路 1、读取离线视频流 2、将视频帧给yolo识别 3、根据识别结果 对视频进行绘制边框、加文字之类的 完整代码如下&#xff1a; import datetimefrom ultralytics …

RTSP/Onvif安防视频EasyNVR平台 vs.多协议接入视频汇聚EasyCVR平台:设备分组的区别

EasyNVR安防视频云平台是旭帆科技TSINGSEE青犀旗下支持RTSP/Onvif协议接入的安防监控流媒体视频云平台。平台具备视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力&#xff0c;能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、W…

大模型日报|今日必读的10篇大模型论文

大家好&#xff0c;今日必读的大模型论文来啦&#xff01; 1.谷歌推出新型 Transformer 架构&#xff1a;反馈注意力就是工作记忆 虽然 Transformer 给深度学习带来了革命性的变化&#xff0c;但二次注意复杂性阻碍了其处理无限长输入的能力。 谷歌研究团队提出了一种新型 T…

结对编程 300道四则运算

小学老师要每周给同学出300道四则运算练习题。 –这个程序有很多种实现方式:C/C++ C#/VB.net/Java Excel Unix Shell Emacs/Powershell/Vbscript Perl Python –两个运算符,100 以内的数字,不需要写答案。 –需要检查答案是否正确,并且保证答案在 0..100 之间 –尽可能地多设…

为什么说linux操作系统要比windows稳定?

正常人说windows的时候是指一整套桌面系统&#xff0c;而说linux的时候是一个命令行内核。后者从原理上就比前者稳定。 如果你日常使用的是linux的发行版桌面系统&#xff0c;看到这话估计直接想骂娘。就我12年的ubuntu使用体验来说&#xff0c;定期备份系统是必须的&#xff…

文献速递:深度学习胰腺癌诊断--胰腺癌在CT扫描中通过深度学习检测:一项全国性的基于人群的研究

Title 题目 Pancreatic Cancer Detection on CT Scans with Deep Learning: A Nationwide Population-based Study 胰腺癌在CT扫描中通过深度学习检测&#xff1a;一项全国性的基于人群的研究 01 文献速递介绍 胰腺癌&#xff08;PC&#xff09;的五年生存率是所有癌症中…

原型设计工具的分析

一、原型设计工具的分析 墨刀(Modo) 适用领域: 主要面向移动应用的原型设计 特别适合iOS和安卓平台的应用原型 优点: 用户体验:对于APP原型设计体验非常好,界面友好,操作直观。 控件和布局:控件拖拽和大小调整能够自动匹配相应的设备大小。 平台适配:提供基于iOS和安卓…

Centos7 搭建Mongodb 分片集群4.0/ PSA(三成员副本集)

MongoDB 简介:1、优点和缺点:2、MongoDB适用的业务场景:Centos7 搭建Mongodb 分片集群一、安装MongoDB社区版4.01、配置程序包管理系统(`yum`)2、安装对应版本的MongoDB软件包。3、创建运行mongodb的目录并禁用SELinux4、修改文件打开数5、初始化系统5.1、创建config配置…

VMware 虚拟机中的 Ubuntu 16.04 设置 USB 连接

VMware 虚拟机中的 Ubuntu 16.04 设置 USB 连接 1. VMware USB Arbitration Service2. 可移动设备 USB 口连接主机3. 虚拟机 -> 可移动设备 -> 连接 (断开与主机的连接)4. 状态栏 -> 断开连接 (连接主机)References 1. VMware USB Arbitration Service 计算机 -> …