首页 > 编程语言 >C++_线程池代码看C++类-模板-标准库

C++_线程池代码看C++类-模板-标准库

时间:2023-12-04 18:24:22浏览次数:35  
标签:emplace 函数 C++ 运算符 线程 模板 构造函数

C++线程池

线程池的组成部分:
    线程池管理器(ThreadPoolManager):用于创建并管理线程池
    工作线程(WorkThread): 线程池中线程
    任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
    任务队列:用于存放没有处理的任务。提供一种缓冲机制。
    	
    通过新建一个线程池类,以类来管理资源
        3个公有成员函数与5个私有成员
    
    构造函数接受一个size_t类型的数,表示连接数
    enqueue表示线程池部分中的任务管道,是一个模板函数
https://github.com/progschj/ThreadPool/blob/master/ThreadPool.h 	

C++标准库

 C++ 三个主要方面: 类,模板,标准库
   C++面向对象技术,模板(泛型编程),内存管理
C语言中有三座大山:指针、递归、数据结构。而数据结构有3种必须掌握:Vector、链表、二叉树
容器
 C++ 11标准中加入了unordered系列的容器。
   unordered_map记录元素的hash值,根据hash值判断元素是否相同。
   unordered_map 容器中	 存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的 
  map相当于java中的TreeMap,unordered_map相当于HashMap 
    结构体用map 重载<运算符,结构体用unordered_map 重载==运算符。
unordered_map模板
unordered_map的迭代器 是一个指针,指向这个元素,通过迭代器来取得它的值	

成员函数: begin  end  size empty   
   emplace  构造及插入一个元素 
   emplace_hint 按提示构造及插入一个元素 
   insert    插入元素
   emplace() 或者 emplace_hint() 方法,它们完成“向容器中添加新键值对”的效率,要比 insert() 方法高 

模板

模板是基于用户为模板参数提供的参数在编译时生成普通类型或函数的构造
 调用函数模板,编译器私底下会 根据传过来的变量创建对应的函数,将它具体化。——这就是通过编译生成的模板函数。
  C++中的模板可以分为两种类型:函数模板和类模板
      函数模板使用一个或多个类型参数作为函数参数,从而定义了一组可重用的函数代码
      
      类模板使用一个或多个类型参数作为类成员的类型,从而定义了一组可重用的类代码
 
使用省略号运算符 (...) 定义采用任意数量的零个或多个类型参数的模板
 template<typename... Arguments> class vtclass;	
	 尖括号<>中,typename和class的作用都一样,都是用作来申明后面的参数是一个虚拟的数据参数类型
     参数均为默认值的模板时,请使用空尖括号		

vector

template <class T, class Allocator = allocator<T>> class vector;

template <class... Args>
pair<iterator, bool> emplace ( Args&&... args );
 输入: 其中,参数 args 表示可直接向该方法传递创建新键值对所需要的 2 个元素的值,其中第一个元素将作为键值对的键,另一个作为键值对的值
 当 emplace() 成功添加新键值对时,返回的迭代器指向新添加的键值对,bool 值为 True;
     当 emplace() 添加新键值对失败时,说明容器中本就包含一个键相等的键值对,
	 此时返回的迭代器指向的就是容器中键相同的这个键值对,bool 值为 False。
 输出:该方法的返回值为 pair 类型值,其包含一个迭代器和一个 bool 类型值

 说明:empalce系列函数通过直接构造对象的方式避免内存拷贝和移动
  调用emplace时,则是将参数传递给元素类型的构造函数,emplace成员使用这些参数在容器管理的内存空间中直接构造元素,没有拷贝操作。
  使用 emplace() 或 emplace_hint() 插入键值对的过程是,直接在 map 容器中的指定位置构造该键值对
   
    emplace_back 如果类或者结构体中没有提供构造函数,那么就不能使用emplace系列函数进行替换
   但是,若key原本就已经存在,则insert只需完成键的对比就可以直接返回了,
       而emplace将必须原地构造一个新的对象才能开始对比,使用emplace将需要额外的构造开销。
   有emplace_front、emplace_back。分别对应容器的
   原有操作insert、push_front、push_back。
   将元素插入到一个指定的位置、将元素插入到容器头部、将元素插入到容器尾部。 
    insert():
        调用构造函数
        调用移动构造函数
        调用移动构造函数
    emplace():
        调用构造函数

函数类型

1.函数返回值类型都是在首位,例如:int GetType();
  C++11开始引入了尾置返回类型,将函数返回值类型放置在函数尾部(如果函数声明与实现写在一起,则放置在函数体之前),
  使用->符号隔开,并将首位的返回值使用auto关键字替代			
	这种类型一般用于返回类型比较复杂的函数用于简化函数定义(比如数组指针)或者某些特殊的结
	  auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>; 
	  //利用尾置限定符  std future用来获取异步任务的结果
  运用于lambda表达式:[] (int a, int b) -> int { return a + b; }	  
2.在C++中,有时我们需要获取函数或可调用对象的返回值类型,以便进行后续的操作
         C++11引入了std::result_of和std::result_of_t(C++14),这两个模板可以方便地获取函数或可调用对象的返回值类型。
 而在C++17中,废弃了std::result_of而引入了更好用的 std::invoke_result和std::invoke_result_t

3.C++11中提供了std::bind。bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的
    template< class F, class... Args >
    /*unspecified*/ bind( F&& f, Args&&... args );
     
    template< class R, class F, class... Args >
    /*unspecified*/ bind( F&& f, Args&&... args );
函数对象,比如函数对象、函数指针、函数引用、成员函数或者数据成员函数。
 args 为函数的入参列表,使用命名空间占位符std::placeholders::_1(第1个参数),std::placeholders::_2(第2个参数)等标志参数。

C++默认成员函数

六个默认成员函数:默认成员函数:用户没有显式实现,编译器会生成的成员函数
 没有自定义的移动构造函数、移动赋值运算符、拷贝构造函数,拷贝赋值运算符或者析构函数时
  编译器会自动生成一个非explicit的inline public隐式移动构造函数T::T(T&&)
    构造函数和析构函数 
        构造函数 - 自动调用
        析构函数 - 自动调用
    拷贝构造函数
    运算符重载
    取地址及const
	取地址操作符重载
说明	
    拷贝构造函数和赋值运算符的区别:
             拷贝构造函数:用一个对象初始化创建另一个对象
             赋值运算符重载:两个已经创建的对象,一个赋值给另一个	
    
6个成员函数    
     默认构造函数
     		默认构造函数指不需要参数就能初始化的构造函数。包含无参和所有参数有默认值两种类型的构造函数。
     析构函数
       		
     拷贝构造函数 const Foo& foo
     		复制构造函数指使用该类的对象作为参数的构造函数。可以有其他参数,但必须提供默认值。
     复制赋值运算符 Foo& operator=(const Foo& foo)
     		重载等号=,将该类的对象赋值给已定义对象。
     移动构造函数  Foo&& foo
     		C++11新增,该类的右值对象为参数的构造函数,其余同复制构造函数。
     移动赋值运算符 Foo& operator=(Foo&& foo)
     		同复制赋值运算符,唯一不同是参数为右值
 英文
    拷贝构造函数(copy constructor)、
    拷贝赋值运算符(copy assignment operator)、
    移动构造函数(move constructor):
         一个右值引用(rvalue reference)创建新的对象,而无需进行深拷贝(deep copy)
    	 构造函数后面写 noexcept
    移动赋值运算符(move assignment operator)

内联函数

 C语言给出的办法是——宏: 在预处理阶段就会将函数与程序中对应的语句进行替换,进而优化了多次调用函数所开辟的函数栈帧。
 C++中替代宏的方法
      由于宏有这三个缺点,C++中给出了替代宏的方法:
      (1)常量定义换用const enum    const enum是C语言中就有的
      (2)短小函数定义换用内联函数 使用inline关键字修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,因此没有函数调用建立栈帧的开销,进而提升程序运行的效率。
   内联函数的声明和定义分离会导致链接错误,所以使用内联函数就直接在该源文件中定义
 类的声明和实现分开
类内声明
外联是相对于内联说的,只有类才有内联外联函数。类的成员函数可以分为内联函数和外联函数	 
类内定义:将函数的函数体定义在类内  
     类内定义与内联函数的关系:类内定义就是默认为inline内联函数
类外定义:
    类外定义就是函数体在类外面,分为同文件类外定义和分文件类外定义  

inline 是对编译器的建议	
外联函数是声明在类体内,定义在类体外的成员函数。外联函数的函数体在类的实现部分		

使用

 #include "ThreadPool.h"
  ThreadPool pool(4); 
     pool.enqueue([i] 

参考

详细介绍C++STL:unordered_map  https://www.cnblogs.com/langyao/p/8823092.html	          	

标签:emplace,函数,C++,运算符,线程,模板,构造函数
From: https://www.cnblogs.com/ytwang/p/17875621.html

相关文章

  • 一. C++基础
    文章参考:《C++面向对象程序设计》✍千处细节、万字总结(建议收藏)_白鳯的博客-CSDN博客1.一个简单的案例#include<iostream>//编译预处理命令usingnamespacestd;//使用命名空间intadd(inta,intb);//函数原型说明intmain()//主函数{ intx,y;......
  • 2021 最佳 C++ IDE 排行
    2021最佳C++IDE排行 BlogAuthor:DoriExtermanPublishedOn:5月31,2021Estimatedreadingtime:1minutes想把所有优秀的 IDE(集成开发环境)或类似 IDE 的工具在一篇文章内梳理出来,比登天还难。不过,JetBrains的调查数据显示,75% 的受访者经常使用 IDE。这些工具推......
  • 六. 函数模板和类模板
    文章参考:《C++面向对象程序设计》✍千处细节、万字总结(建议收藏)_白鳯的博客-CSDN博客1.引入在编写函数和类时,有时会出现这样的情况,具体实现方式完全一致,但因此参数类型、返回值类型、数据类型等因素的不同,导致不得不写多个函数或者类(因为C++是强类型语言,无法隐式转换,且有些......
  • 最佳 C++ 编译器
    最佳C++编译器Incredibuild​已认证账号​关注 134人赞同了该文章 C++是一个“开放”的编程语言,任何人都可以使用自己喜欢的编译器。当然,C++编译器的种类也很多。同样, C++IDE 也不少,我在之前的一个博客中讨论过这个话题。编译和运行C++......
  • C++ 内联函数 inline
    宏定义实现和普通函数实现:-宏定义是直接在实现的时候进行代码替换,可能产生结果异常问题。-普通函数实现:调用函数进出函数体的时候时间开销可能过大。1#include<iostream>2usingnamespacestd;3//宏实现4#defineGETMAX(a,b)((a)>(b)?(a):(b))......
  • c++ friend关键字 友元
     在C++中,friend关键字用于声明友元函数或友元类1。友元函数或友元类可以访问当前类的私有成员和保护成员,即使它们不是当前类的成员函数或成员类1。友元函数是一个独立的函数,而友元类是一个类可以访问另一个类的私有成员和保护成员1。例如,如果要声明函数为一个类的友元,需要......
  • Java两个线程间如何进行数据交互
    共享变量:可以通过在两个线程中定义一个共享变量,然后使用synchronized(volatile)关键字确保线程安全,实现数据的读取和修改。publicclass共享变量01{privateintvalue;publicsynchronizedintgetValue(){returnvalue;}publicsynchronizedvo......
  • jmeter测试计划中的“独立运行每个线程组”Demo演示
    一:jmeter的运行顺序测试计划-->线程组其次执行顺序为:配置元件、前置处理器、定时器、取样器、后置处理器、断言、监听器当一个测试计划中有多个线程组,当多个线程组都是是执行状态时,就会用到测试计划中的“独立运行每个线程组”勾选框不勾选时的执行顺序如下:......
  • 原来这才是 JDK 推荐的线程关闭方式,别再乱用了!
    原文:juejin.cn/post/7291564831710445622JDK在线程的Stop方法时明确不得强行销毁一个线程,要优雅的退出线程。何谓优雅退出线程,即业务将进行中请求正确被处理,取消待执行请求,执行资源回收,最终ThreadRunablerun方法return结束执行。首先问为什么要退出一个线程,再提问如何退出......
  • C++U5-08-二叉树1
    上节课作业分析讲解视频链接:https://pan.baidu.com/s/1_jaM_TlZmLJX4JbLuJtKzA?pwd=2us4提取码:2us4学习目标  树在C++中,二叉树是一种常用的数据结构,由节点(Node)组成,每个节点可以有最多两个子节点。二叉树具有以下几个主要的作用:存储和组织数据:二叉树可用于存储和组织大......