C++标准库

二、C++标准库

1.string

#include <iostream>
#include <string>
1.1构造
//赋值构造
string str = "zxm";
//无参构造,构造一个空字符串,构造之后可以通过=进行赋值
string str2;
//用char *构造
string str3("zxm");
//重复字符构造,输出11个a
string(11,'a');
//拷贝构造  str2和str5内容是一样的
string str5(str2);
//移动拷贝   str2没有内容,移动到str6里去了
string str6(move(str2));
//用指定范围内的字符进行构造,从第四个下表开始,取三个给str7
string str7(str2,4,3);
//字符串拼接
string str8+str2+"111";
1.2 元素访问
string str="hello world";
str[1]='E';
str.at(1)='E';
//第一个字符
cout << str.front() << endl;
//最后一个字符
cout << str.back() << endl;
//data() c_str   获取数据
cout << str.data() <<endl;
​
1.3容量操作
//判断是否为空  返回0、1   true、false
string str = "hello world";
cout << boolalpha << str3.empty() <<endl;
//字符串中的大小和长度
cout << str.size() << endl;
cout << str.length() << endl;
//字符串对象最大的容量
cout str.max_size() << endl;
//截取前几个字符
cout << str.resize(10) << endl;
//已经分配的内存容量
cout << str.capacity() << endl;
//分配内存大小
str.reserve();
//没有用到的内存释放掉
str.shrink_to_fit();
1.4迭代器

迭代器:为容器类提供统一的遍历接口,不用管容器底层内存管理方式。

1.(正向)迭代器 iterator

2.(正向)只读迭代器 const_iterator

3.反向迭代器 reverse_iterator

4.反向只读迭代器 const_reverse_iterator

string str = "hello world";
//指向第一个位置
string::iterator it = str.begin();
//输出h
cout << *it <<endl;
//输出l
it+=3;
cout << *it < endl;
//可以修改,如果是只读迭代器的话,就不可以修改了
*it ='E'
//循环遍历
for(;it!=str.end();it++){
    cout << *it <<endl;
}

反向迭代器:

string::reverse_iterator it = str.rbegin();
//循环遍历
for(;it!=str.rend();it++){
    cout << *it <<endl;
}
1.5string比较相关操作
//==
string str="hello world";
string str2="Hello World";
cout << std::boolalpha <<(str==str2) <<endl;   //返回true  or  false
//compare
cout << str.compare(str2) <<endl;
//判断是否以指定的内容开始或者结尾
cout << boolalpha << str.starts_with("hello") << endl;
cout << boolalpha << str.ends_with("jpg") <<endl;   //可以判断后缀名
//判断字符串中是否含有某些内容
cout << boolalpha << str.contains("txt") <<endl;
1.6插入和删除操作
string str="hello world";
//在现有的字符串基础上再加E
str.push_back("E");
//把最后一个字符串给删除
str.pop_back();
//在字符串基础上追加内容,就是在最后开始追加
str.append(3,'A');  //追加三个A
str.append(3,'A').append(2,'B');
str.append(str2);
//从第三个字符开始追加
str.append(str2,3);
str.append("Nice");
str.append(str2.begin(),str2.begin()+3);
//insert() 在指定位置插入字符
str.insert(2,3,'C');  //从索引为2开始插入三个C
str.insert(2,str2,5,2);
//清除字符串的所有内容
str.clear();
//清楚指定位置
str.erase(2,2);   //从2开始 清除两个字符
str.erase(str.begin()+2);  //从str开始的第二个字符开始清除
ser.erase(str.begin()+2,str.begin()+5);   //清除[2,5)字符
                                            
1.7 替换子串
string str = "hello world";
string str2="北国风光";
string str3 = "hello Cpp";
str.replace(2,1,str2) ;  //索引为2的字符替换一个字符  替换成str2    he北国风光lo world
//取字符串
cout << str.substr(3) << endl;  //从索引3开始提取
cout << str.substr(3,2) << endl;  //从索引3开始提取2个字符
1.8查找
string str = "AAABBBCCCDDD"
//返回查到的第一个字符的索引号   找不到返回npos(-1)
cout << str.find("AA") <<endl;
int index = str.find("KDKD");
if(string::npos==index){
    cout << "没找到" << endl;
}else{
    cout <<  "找到了" <<endl;
}
//从后面往前找
str.rfind();
//找最先出现的字符的位置  
str.find_first_of("EECD");
//返回B的索引
str.find_first_not_of("AAA");
//从后往前找
find_last_of();
find_last_not_of();
1.9其他操作
to_string();  //将数组转化为string
str+to_string(12);
//将string转换为数字
cout << stoi(str2,&n,16) << endl;  //将str2转换为16进制的数字,返回转换的个数n
cout << n << endl;
//将string转换为浮点型:DOUBLE,float
cout << stod(str2) << endl;
stof;
//计算hash值
cout << hs(str) <<endl;
1.10 string_view
const char *s="望长城内外";
string_view sv = s;
​

这样 sv和s都是指向同一个地址。否则,正常的string会再会创建另一个地址把内容存进去 节省了内存空间

//移除六个字节
sv.remove_prefix(6);
cout << sv << endl;
//从后面移除字节数
sv.remove_suffix(6);

2.容器

2.1array

静态的连续数组

//头文件
#include<array>
//创建
array<int,5> arr = {1,2,3,4,5};
cout << arr[0] <<endl;
cout << arr.at(0) <<endl;
//填充   将这五个位置都给填充上
array<int,5> arr;   //可以存储自己定义的数据类型
arr.fill(111);  
for(auto &n :arr){
    cout  << n << endl;  //输出:111 111 111 111 111
}
//使用迭代器遍历
array<int,5>::iterator it = ar.begin();
for(;it!=arr.end();it++){
    cout  << *it << endl;
}
2.2vector

动态的连续数组 大小是变化的

#include<vector>
//声明
vector<int> vec;     //int 可以替换成对象
cout << vec.size() << endl;
cout << vec.capacity() << endl;
for(auto &n : vec){
    cout << n << "\t";
}
//分配了三个元素的大小 用100来填充
vector<int> vec(3,100);
//分配了10个元素的大小 用0来填充
vector<int> vec(10);
#include<vector>
//声明
vector<int> vec(10);  //分配十个内存大小
//插入
vec.push_back(10);
 //输出地址
cout << (uintptr_t)vec.data() << endl; 
//插入
vec.push_back(122);
//输出地址
cout << (uintptr_t)vec.data() << endl;   
 //大小
cout << vec.size() << endl;
 //分配的大小
cout << vec.capacity() << endl;   
for(auto &n : vec){
    cout << n << "\t";     //输出
}
//分配了三个元素的大小 用100来填充
vector<int> vec(3,100);
//分配了10个元素的大小 用0来填充
vector<int> vec(10);

1.调用无参构造进行初始化

调用了三参构造和移动构造,移动构造将临时变量移动到地址

vector<User> vec(3);  
//在末尾插入user
vec.push_back(User(1,"tom",22)); 

2.调用拷贝构造

vector<User> vec(3);  
User u1(1,"tom",22);
vec.push_back(u1);
​
User u2(1,"Jey",22);
vec.push_back(u2);

首先是u1的三参构造,然后就是拷贝对象,因为要拷贝到里面那个位置上

首先是u2的三参构造,然后就是拷贝对象。然后u1又进行了一次对象拷贝

内存分配的问题。给u2的内存分配完成后,将u1拷贝到u2的前面的那个位置

3.能不能不进行拷贝或者移动

vec.emplace_back(2,"jj",21);  //插入

只进行了一次三参构造

vec.emplace_back(); 

只进行了一次无参构造

vec.emplace(vec.begin()+1,3,"Le",4);
3.单向链表-forward_list

声明:

#include<forward_list>
forward_list<int> fs = {2,4,1,9,3}
forward_list<int> fs2 = {5,8,1,6,9}

只能通过自增的方式一步一步的往后移

forword_list<int>::iterator it = fs.begin();
it++;

擦除元素

it++;
it++;
fs.erase_after(it); // 擦除it后面的元素  9被擦除了
for(auto &i : fs){
    cout << i << "\t";
}

合并元素

fs.merge(fs2);   //fs和fs2合并在一起  但是是无序的
//可以先排序,再合并 
fs.sort();
fs2.sort();
fs.merge(fs2);   //这样合并之后就是有序的了   把fs2合并到fs里面  fs2就没有内容了
​

指定位置合并

fs.splice_after(it,fs2);   //在1后面把指定的链表插入进去

移除指定的值

fs.remove(8);   //移除8

//根据条件移除对应的内容

bool pre(const int &n){
    return n<4;
}
fs.remove_if(pre);  //把<4的内容移除掉  对fs的每个元素用提供的函数做判断
fs.remoce_if([] (const int& n){return n<4});

//升序

fs.sort();

//逆序,降序

bool cmp(const int &a,const int &b){
    return a>b;
}
fs.sort(cmp);
fs.sort([](const int &a,const int &b){return a<b});
greater<int> gt;
fs.sort(gt);
fs.sort(greater<int>());

//移除连续重复的元素

fs.unique();
4.list双链表

和单链表类似

list<int> ls = {1,3,4,5,6,7}
list<int>::iterator it = ls.begin();
it++;
it++;
it--;
cont << *it <<endl;
​
5.栈stack

引入头文件

#include<stack>
stack<string> str_stack;
str_stack.push("zzz");  //入栈   简单的数据类型用push
//取栈顶数据
string str = str_stack.top();
//栈顶元素删除
str_stack.pop();
cout << str << endl;

//出栈

while(!str_stack.empty()){
    string str = str_stack.top();
    str_stack.pop();
    cout << str << endl;
}
6.队列queue

引入头文件

#include<queue>
queue<const char *>q;
q.qush("张三");
q.emplace("赵六"); //多个数据

获取第一个元素

const char *s=q.front();
//出队
q.pop();
cout << s << endl;

循环一次出队

while(!q.empty()){
    const char *s=q.front();
    //出队
    q.pop();
    cout << s << endl;
}
7.双端队列priority_queue 优先队列
priority_queue<int> q;
q.push(10);
q.push(20);
q.push(15);
while(!q.empty()){
    auto top = q.top(); //获取队首元素
    q.pop();
    cout << top <<endl;
}
输出:20  15  10   按照从大到小输出

可以从小到大输出

priority_queue<int,vector<int>,greater<int>> q;   //参数:类型,容器,默认vector,比较器
q.push(10);
q.push(20);
q.push(15);
输出: 10  15  20 
//如果存入的数据是自定义的类,那就需要重载一个<运算符  就可以用默认的比较器比较大小
priority_queue<Persion> q;
q.emplace(60,"Tom");
q.emplace(70,"Jerry");
q.emplace(65,"Lee");
//根据年龄比较大小
//重载<运算符
bool operator < (const Persion &p1,const Persion &p2){
    return p1.getAge() < p2.getAge();
}
输出: 70  65   60

自定义比较器

方式一:模仿less定义的比较器

struct Comp{
    bool operator()(const Persion &p1,const Persion &p2) const{
        return p1.getAge() < p2.getAge();
    }
};
priority_queue<Persion,vector<Persion>,Comp> q;

方式二:定义普通比较函数

bool cmp(const Persion &p1,const Persion &p2){
    return p1.getAge() < p2.getAge();
}
typefdef bool (*cmp2) (const Persion &p1,const Persion &p2);  //宏定义函数指针
priority_queue<Persion,vector<Persion>,cmp2> q(cmp);

方式三:通过lambda表达式定义比较函数

auto cmp3 = [](const Persion& p1,const Persion& p2){
    return p1.getAge() < p2.getAge();
};
priority_queue<Persion,vector<Persion>,decltype(cmp3)> q(cmp3);   //decltype自动类型推导
8.set

不重复

#include<set>
set<int> st {1,3,4,3}  //输出:1  3  4   重复的删除掉了
vector<int> vec = {1,1,2,2,3,3,4,4,5,5};
set<int> st2(vec.begin(),vec.end());   //输出:1 2 3 4 5

判断两个元素是否相等

如何两个对象a和b相互不比较小于对方:!a<b && !a>b 那么认为他们等价

//插入元素节点
st.insert(0);

//把指定元素提取出来

set<int>::node_type node = st.extract(3);  //把3提取出来    
cout << node.value() << endl;

//合并集合 合并的是原先集合没有的

st.marge(st2)

返回元素的个数

st.count()

find:查找指定的值

返回指定的值的下边界,返回的是对应值的下标 返回的是迭代器

cout << *st.lower_bound(3) <<endl;

返回指定的值的上边界,返回的是对应值的下标 返回的是迭代器

cout << *st.upper_bound(3) <<endl;
9.map

pair类型

pair<string,int> p;
p.first = "AGB";
p.second=25;

map返回的pair类型

定义:

#include<map>
map<string,int> mp = {{"张三,120"},{"李四",210},{"王五",200}};
//迭代
for(anto it = mp.begin();it!=mp.end();it++){
    cout << m->first << "-->" << m->second <<endl;  //  张三,120
}
//循环
for(anto &m :mp){
    cout << m.first << "-->" << m.second <<endl;  //  张三,120
}

通过key获取值value

cout << mp.at("张三") << endl;
mp["张三"]

还可以赋值

mp.at("张三")=100;

插入,如果存在,不进行任何操作

mp.insert(pair<string,int>("赵六",3330));
mp.try_emplace("张三",333);

修改,如果不存在,则插入

mp.insert_or_assign("张三",333);
10.bitset

类模板bitset表示一个N位的固定大小的序列,可以用标准逻辑运算符操作bitset 并将他与字符串和整数相互转换。

#include<bitset>
bitset<8> bst("1010111");   //输出二进制 
bitset<8> bst2(121u);  //转换成二进制
cout << bst << endl;
cout << bst2 << endl;
cout << bst2[0] << endl;   取第一个值  从右往左

检测对应的位置 如果位1返回true 如果为0返回false

bst.test(0);  //判断第一个元素是1还是0  
bst.all();  //全部为1返回true
bst.any();  //其中  存在1就返回true
bst.none();  //全部为0返回true

统计1的个数

bst.count();
bst.size();   //返回多少位

把指定位置设定位1

bst.set(0);  //把第一位设置位1

把指定位置设定为0

bst.reset(0);

进行0 1 反转 0的位置变为1 1的位置变为0

bst.filp();

转成字符串

bst.to_string();

转成整形long

bst.to_ulong();
bst.to_ullong();

左移

bst2 = bst2 << 2;
bst<<=2;

按位与

bst & bst2

按位或

bst | bst2

按位异或 不同的为1

bst ^ bst2

取反

~bst
11.bit

判断是大端存储还是小端存储

cout << boolalpha << (endian::native == endian::big) << endl;  //判断是大端吗
cout << boolalpha << (endian::native == endian::little) << endl;  //判断是小端吗

3.算法

1.for_each()
for_each(@begin,@end,f(0));   //开始  结束  函数
​

作用:针对迭代器指定的每一个元素都来调用一下f函数来进行处理

定义

#include<algorithm>
vector<int> vec = {46,72,91,89,36,11};
int a[10] = {60,51,10,63,82,23};
for_each(vec.begin(),vec.end(),fun);
void fun(const int& n){
    cout << n <<endl;
}
for_each(vec.begin(),vec.end(),[](const int& n){
    cout << n <<endl;
});
for_each(a,a+10,f2); 
for_each_n(a,3,f2);  //对前三个值进行操作
2.any_of() all_of() none_of()
vector<int> vec = {46,72,91,89,36,11};
int a[10] = {60,51,10,63,82,23};
cout << any_of(vec.begin(),vec.end(),check) <<endl;  //只要存在满足函数的条件就返回true
cout << all_of(vec.begin(),vec.end(),check) <<endl; //所有的值满足条件返回true、
cout << none_of(vec.begin(),vec.end(),check) <<endl; //没有条件满足返回true
bool check(const int& n){
    return n >90
}
3.count() count_if()
vector<int> vec = {46,72,91,89,36,11};
int a[10] = {60,51,10,63,82,23};
cout << count(vec.begin(),vec.end(),46);  //统计46的值有多少个
cout << count_if(vec.begin(),vec.end(),check)   //统计有多少个大于90 的
bool check(const int& n){
    return n >90
}
4.find() find_if()
vector<int> vec = {46,72,91,89,36,11};
anto it = find(vec.begin(),vec.end(),91);  //查找91
if(it==vec.end()){
    cout << "没找到" << endl;
}else{
    cout << *it <<endl;
}
anto it = find_if(vec.begin(),vec.end(),check);  //返回第一个符合值的索引值
5.queal() mismatch()
vector<int> vec = {46,72,91,89,36,11};
vector<int> vec2 = {46,72,91,89,36,11};
cout << boolalpha <<equal(vec.begin(),vec.end(),vec2.begin(),vec2.endl()) << endl;  //判断vec和vec2是否相等
auto pa = mismatch(vec.begin(),vec.end(),vec2.begin());
cout << pa.first -vec.begin() << endl;  // 判断第几个位置不一样了
6.二分查找

排序:

vector<int> vec = {46,72,91,89,36,11};
vector<int> vec2 = {46,72,91,89,36,11};
int a[10] = {60,51,10,63,82,23,98};
//排容器
sort(vec.begin(),vec.end());    //升序
for_each(vec.begin(),vec.end(),print); 
//排数组
sort(a,a+7,greater<int>());   //降序
for_each(vec.begin(),vec.end(),print); 
void print(const int &n){
    cout << n <<"\t"
}

binary_search():在排好序的容器中,使用二分查找

查到返回true 查不到返回false

cout << binary_search(vec.begin(),vec.end(),63) <<endl;  //查到63返回true

只要能找到就返回true 不需要连着

cout << includes(vec.begin(),vec.end(),vec2.begin(),vec2.end()) << endl; //查找vec中是否还有vec2
7.最大值 最小值

最大值max

cout << max({60,51,10,63,82,23,98}) << endl;  //输出:98  
cout << min({60,51,10,63,82,23,98})  << endl;  //最小值

返回迭代器

vector<int> vec = {46,72,91,89,36,11};
auto it = max_element(vec.begin(),vec.end());   //最大值
auto it = min_element(vec.begin(),vec.end());  //最小值
cout << *it <<endl;

判断是否已经排好序了

cout << is_sorted(vec.begin(),vec.end()) << endl;

判断升序的元素的下一个元素

cout << is_sorted_until(vec.begin(),vec.end()) << endl;  //输出89 ,因为  46  72  91 是升序的

判断奇数和偶数是不是分好组了,还是交叉

cout << is_partitioned(vec.begin(),vec.end()) << endl;
8.复制copy,移动move、交换swapping元素

1.复制copy

vector<int> vec = {46,72,91,89,36,11};
int a[10]={0};
auto end = copy(vec.begin(),vec.begin()+5,a);
for_each(a,end,print); //输出:46,72,91,89,36

指定复制多少个元素

auto end = copy_n(vec.begin(),5,a);

从后往前复制

vector<int> vec = {46,72,91,89,36,11};
int a[10]={0};
auto end = copy_backward(vec.begin(),vec.begin()+5,a+10);
for_each(a,a+10,print); //输出:0,0,0,0,0,46,72,91,89,36

按条件复制

vector<int> vec = {46,72,91,89,36,11};
int a[10]={0};
auto end = copy_if(vec.begin(),vec.begin()+5,a,check);
for_each(a,end,print); //输出:46,72,36
bool check(const int& n){
    return n%2==0
}

2.移动move

vector<string> v2 = {"A","B","C","D","E","F"};
string s2[5];
move(v2.begin(),v2.end()-3,s2);
for(auto &&i :v2){
    cout << i <<"\t";
}

3.随机采样sample

//从里面随机取出数据
vector<int> vec = {46,72,91,89,36,11};
int a[10]={0};
auto end = sample(vec.begin(),vec.end(),a,3,default_random_engine(random_device{}());//随机取3个数
for_each(a,end,print); //输出:46,72,89,

4.交换 iter_swap

vector<int> vec = {46,72,91,89,36,11};
int a[10]={0};
iter_swap(vec.begin(),a);
for_each(a,a+10,print);    46,0,0,0,0,0
cout << endl;
for_each(vec.begin(),vec.end(),print);  0,72,91,89,36,11

自身两个元素进行交换

vector<int> vec = {46,72,91,89,36,11};
iter_swap(vec.begin(),vec.begin()+1);  //72,46,91,89,36,11

交换一个范围

iter_ranges(vec.begin(),vec.begin()+5,a);

4.数值库-随机数生成

引入头文件

#include<random>
random_device rd;
//随机生成一个数
cout << rd() <<endl;
//确定随机数生成器
default_random_engine re(rd());
//设置随机数的分布
uniform_int_distribution<> dis{20,30}; //随机生成20-30之间的数  均匀分布
//生成随机数
cout << dis(re) <<endl;

5.通用工具库

5.1-智能指针

用了智能指针就不用手动释放了

int *ptr = new int;
unique_ptr<int> p(ptr);
*p = 10;
cout << *p <<endl;
nuique_ptr<User> p(new User(1,"Tom",11));
nuique_ptr<User> p = make_unique<User>(1,"Tom",11);
nuique_ptr<User[]> p = make_unique<User[]>(10);  //10:数组大小
5.2 tuple
#include<tuple>
int main(){
    tuple<int,int,string> tp = {12,100,"Tom"};  //初始化
    cout << get<1>(tp) << endl;   //访问方式,获取第二个数:100
    
    auto [a,b,str] = tp; 
    return 0;
}
5.3 function

C++ 标准库中的 <functional> 头文件提供了一组函数模板,这些模板允许我们使用函数对象(function objects)作为参数传递给算法,或者作为算法的返回值。函数对象是那些重载了 operator() 的对象,它们可以像普通函数一样被调用。

#include <iostream>
#include <functional>
​
void greet() {
    std::cout << "Hello, World!" << std::endl;
}
​
int main() {
    std::function<void()> f = greet; // 使用函数
    f(); // 输出: Hello, World!
​
    std::function<void()> lambda = []() {
        std::cout << "Hello, Lambda!" << std::endl;
    };
    lambda(); // 输出: Hello, Lambda!
​
    return 0;
}

使用 std::bind

std::bind 允许创建一个可调用对象,它在调用时会将给定的参数绑定到一个函数或函数对象。

#include <iostream>
#include <functional>
​
int add(int a, int b) {
    return a + b;
}
​
int main() {
    auto bound_add = std::bind(add, 5, std::placeholders::_1);  //std::placeholders::_1之绑定一个参数
    std::cout << bound_add(10) << std::endl; // 输出: 15
​
    return 0;
}

6.文件系统库

1.path

引入头文件

#include<filesystem>
namespace fs = std::filesystem;
fs::path pth="D::\\Users\\ZZ";
//获取当前路径
fs::path pth2=fs::current_path();
cout << pth2 <<endl;

追加路径

fs::path pth="D::\\Users\\ZZ";
pth.append("aaa"); //输出:D::\\Users\\ZZ\\aaa
pth /=aaa;   //输出:D::\\Users\\ZZ\\aaa
pth.concat("aaa")  //D::\\Users\\ZZaaa

移除文件名

pth.remove_filename();  //只会移除最后一个,不会判断是否是文件名

替换文件名

pth.replace_filename("KKK");  //只会移除最后一个,不会判断是否是文件名
pth.replace_extension("jpg");  //替换扩展名

转换成string

cout << pth.string()  <<endl;

root_path:返回根路径

relative_path:返回相对路径

filename:返回文件名

stem:返回文件主干部分

extension:返回文件扩展名

empty:检查路径字符串是否问空

2.directory_iterator
fs::path pth=fs::current_path();
//获取当前目录下的所有内容
fs::directory_iterator di(pth);
for(const fs::directory_entry &entry:di){
    cout << entry.path() << endl;  //输出所有目录
}
entry.is_directory();  //判断是否是目录
entry.is_regular_file(); //判断是否为文件
entry.file_size()  //文件大小

用迭代器的方法输出

for(anto it = begin(di);it!=end(di);it++){
    cout << it->path() <<endl;
}

子目录也输出了

fs::recursive_directory_iterator di(pth);
3.其他

1.文件或者目录复制:copy

fs::copy(pth / "text.cpp", pth / "haha.cpp");  //把text.cpp复制到了haha.cpp

2.创建目录

fs::path pth = fs::current_path();
cout << fs::create_directory(pth / "aaa") <<endl;  //在当前目录下创建aaa目录
cout << fs::create_directories(pth / "aaa/cc") <<endl;   //创建多层目录

7.chrono库:事件日期工具

引入头文件

#include<chrono>

1.时间点

//获取当前时间:1970年到现在时间的时间段  纳秒级别
chrono::time_point<chrono::system_clock,chrono::nanoseconds> t1 = 
    chrono::system_clock::now();
//获取当前时间:1970年到现在时间的时间段
chrono::system_clock::time_point t1 = chrono::system_clock::now();
//转换成秒级别
chrono::time_point<chrono::system_clock,chrono::seconds> t2 = 
    chrono::time_point_cast<chrono::seconds>(t1);
cout << t2.time_since_epoch() << endl;

2.时间段:duration

头文件

#include<ratio>
chrono::duration<int> d(10);
cout << d <<endl; //10s
chrono::duration<int,ration<60>> d(10);
cout << d <<endl; //10min
chrono::duration<int,ration<3600>> d(10);
cout << d <<endl; //10h
​
chrono::duration<int,std::nano> d(10);  //10ns
​
auto duration = std::chrono::seconds(5);  //5s
chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
chrono::nanoseconds d = t1.time_since_epoch();
cout << d <<endl;    
chrono::duration<double> d = t2-t1
#include<thread>
cout << "start" << endl;
this_thread::sleep_for(chrono::seconds(2));//本线程休眠多久
cout << "end" << endl;

8.线程库

1.thread

引入头文件

#include<thread>
int i = 0;
void tf(){
    while(i<10){
        cout << "子线程" << i <<endl;
        this_thread::sleep_for(chrono::milliseconds(10));
        i++;
    }
}
​
int main(){
    thread th(tf)  //用thread声明一个对象,把需要启动的函数给放进去
    while(i<10){
        cout << "主线程进行中" << i <<endl;
        this_thread::sleep_for(chrono::milliseconds(10));
        i++;
   }
   th.join();  //主线程等待
   return 0;
}
class A{
private:
    int i;
public:
    void fn(){
        i = 0;
        while(i<10){
            cout << "A::fn" << i <<endl;
            i++;
            this_thread::sleep_for(chrono::milliseconds(10));
        }
    }
    void fn2(int num){
        cout << "A::fn num = " << num <<endl;
        num+=100;
    }
};
int main(){
    A a;  //声明对象
    thraed th(&A::fn,&a); //无参数:用类中的方法进行启动   需要启动的类里面的函数指针传给他  对应的对象的指针也传给他
    thraed th(&A::fn2,&a,num);  //有参数  把参数方后面
    while(i<10){
        cout << "主线程进行中" << i <<endl;
        this_thread::sleep_for(chrono::milliseconds(10));
        i++;
   }
   th.join();  //主线程等待
   return 0;
}
​

如何让子线程改变全局变量的值,则

void fn2(int &num){
     cout << "A::fn num = " << num <<endl;
     num+=100;
}
thraed th(&A::fn,&a,ref(num));  //使用引用包装器ref包装一下

问题:输出流对象和变量i会抢占他们的使用权

2.互斥量(mutex)

为了避免多个线程同时访问共享资源。这会避免竞争,并提供线程间的同步支持。

lock:锁定互斥

try_lock 尝试锁定互斥

unlock 解锁互斥

引入头文件

#include<mutex>

声明mutex对象

mutex mtx;
int i = 0;
void tf(){
    while(i<10){
        mtx.lock();  //加锁
        cout << "子线程" << i <<endl;
        i++;
        mut.unlock();   //解锁
        this_thread::sleep_for(chrono::milliseconds(10));
    }
}
​
int main(){
    thread th(tf)  //用thread声明一个对象,把需要启动的函数给放进去
    while(i<10){
        mtx.lock();  //加锁
        cout << "主线程进行中" << i <<endl;
        i++;
        mut.unlock();   //解锁
        this_thread::sleep_for(chrono::milliseconds(10));
   }
   th.join();  //主线程等待
   return 0;
}

3.lock_guard

实现锁的自动管理

int i = 0;
mutex mtx;
void tf(){
    while(i<10){
        lock_guard<mutex> lock(mtx); //自动进行加锁,作用范围结束后解锁
        cout << "子线程" << i <<endl;
        i++;
        this_thread::sleep_for(chrono::milliseconds(10));
    }
}
​
int main(){
    thread th(tf)  //用thread声明一个对象,把需要启动的函数给放进去
    while(i<10){
        lock_guard<mutex> lock(mtx); //自动进行加锁,作用范围结束后解锁
        cout << "主线程进行中" << i <<endl;
        i++;
        this_thread::sleep_for(chrono::milliseconds(10));
   }
   th.join();  //主线程等待
   return 0;
}

4.unique_lock

unique_lock<mutex> lk(mtx); //自动进行加锁,作用范围结束后解锁
unique_lock<mutex> lk(mtx,std::defer_lock); //延迟锁定  必须手动加锁
lk.lock()
3.条件变量

主线程和子线程一个一次交替进行

wait:阻塞当前线程 直到条件变量被唤醒

wait_for: 阻塞当前线程,直到条件变量被唤醒,或到指定的时长以后

wait_until:阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点

引入头文件

#include<condition_variable>
condition_variable cv;   //条件变量对象
bool sub_run = false;  //控制子线程或者主线程谁先运行
int i = 0;
mutex mtx;
void tf(){
    while(i<10){
        unique_lock<mutex> lk(mtx);  //定义一个锁
        cv.wait(lk,[&] {return sub_run;});//在这个地方等待,如果sub_rune为true,那么他会往下执行,如果为fasle那么他会                                               一直等着   [&] {return sub_run;}
        cout << "子线程" << i <<endl;
        i++;
        this_thread::sleep_for(chrono::milliseconds(10));
        sub_run = false;
        cv.notify_all();  //唤醒等待的线程
    }
}
​
int main(){
    thread th(tf)  
    while(i<10){
        cv.wait(lk,[&] {return !sub_run;});
        cout << "主线程进行中" << i <<endl;
        i++;
        this_thread::sleep_for(chrono::milliseconds(10));
        sub_run = false;
        cv.notify_all();  //唤醒等待的线程
   }
   th.join();  //主线程等待
   return 0;
}

启动三个线程轮流输出ABC

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std; 
​
class PrintChar
{
private:
    int loop_num;
    int index;
    mutex mtx;  //互斥量
    condition_variable cv;  //条件变量
public:
    PrintChar(int loop_num) : loop_num(loop_num), index(0) {}
    void A()
    {
        for (int i = 0; i < loop_num; i++)
        {
            unique_lock<mutex> ulk(mtx);
            cv.wait(ulk, [&]() { return index % 3 == 0; });
            cout << "A";
            this_thread::sleep_for(chrono::milliseconds(100));
            index ++;
            cv.notify_all();
        }
​
    }
    void B()
    {
        for (int i = 0; i < loop_num; i++)
        {
            unique_lock<mutex> ulk(mtx);
​
            cv.wait(ulk, [&]() { return index % 3 == 1; });
            cout << "B";
            this_thread::sleep_for(chrono::milliseconds(100));
            index ++;
            cv.notify_all();
        }
​
    }
    void C()
    {
        for (int i = 0; i < loop_num; i++)
        {
            unique_lock<mutex> ulk(mtx);
            cv.wait(ulk, [&]() { return index % 3 == 2; });
            cout << "C";
            this_thread::sleep_for(chrono::milliseconds(100));
            index ++;
            cv.notify_all();
        }
​
    }
​
};
​
int main()
{
    int num = 0;
    cout << "请输入循环次数:" ;
    cin >> num;
​
    PrintChar p(num);
    thread th1(&PrintChar::A, &p);
    thread th2(&PrintChar::B, &p);
    thread th3(&PrintChar::C, &p);
​
    th1.join();
    th2.join();
    th3.join();
​
    return 0;
}
4.单次调用

声明once_flag这个标志

once_flag flag;
void tf(){
    call_once(flag,init,this_thread::get_id());
}
5.Future

标准库提供了一些工具来获取异步任务(即在单独的线程中启动的函数)的返回值,并捕捉其所抛出的异常。

引入头文件

#include<future>
#include <vector>
#include <thread>
#include <future>
#include <iostream>
#include <chrono>
​
using namespace std;
​
void sumfromto(int start, int end, promise<int> ps)
{
    int sum = 0;
    for (int i = start; i <= end; i++)
    {
        sum += i;
    }
    ps.set_value(sum); //可以放在其他地方
}
​
int main()
{
    promise<int> ps; //声明promise的变量
    future<int> sum_future = ps.get_future(); //声明future变量
    thread th(sumfromto, 1, 100, move(ps));  //声明线程,移动的方式传递过去
    cout << sum_future.get() << endl;  //获取
    th.join();
}
6.async

也是开启一个线程 ,返回的future

void sumfromto(int start, int end)
{
    int sum = 0;
    for (int i = start; i <= end; i++)
    {
        sum += i;
    }
    return sum;
}
​
int main()
{
    //future<int> f1 = async(paralell_sum,1,100);
    future<int> f1 = async(std::launch::deferred,paralell_sum,1,100);  //子线程延迟启动,在调用get时启用
    cout << "主线程进行" << endl;
    cout << f1.get() << endl;  //获取对应的值
    return 0;
}

线程开启方式:thread, packaged_task, async

7.原子操作

它允许无锁并发编程

声明一个原子变量

#include<atomic>
atomic_int total(0);
#include <iostream>
#include <vector>
#include <chrono>
#include <thread>
#include <mutex>
#include <atomic>
​
using namespace std; 
​
// int total(0);
atomic_int total(0);
mutex mtx;
​
void fun()
{
    for (int i = 0; i < 1000000; i++)
    {
        // mtx.lock();
        total ++;
        total --;
        // mtx.unlock();
    }
​
}
​
int main()
{
    auto start = chrono::steady_clock::now();
​
    vector<thread> vec;
    for (int i = 0; i < 8; i++)
    {
        vec.emplace_back(fun);
    }
​
    for (int i = 0; i < 8; i++)
    {
        vec[i].join();
    }
    cout << "total = " << total << endl;
    auto end = chrono::steady_clock::now();
    auto dur = chrono::duration_cast<chrono::milliseconds>(end - start);
    cout << dur << endl;
    return 0;
}
  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值