C++11新特性以及std::thread多线程编程

5 篇文章 0 订阅

一 .C++11新特性

1. auto 类型推导
1.1 当=号右边的表达式是一个引用类型时,auto会把引用抛弃,直接推导出原始类型;
1.2 当=号右边的表达式带有const属性时,auto不会使用const属性;
1.3 当const 和引用结合时,auto将保留表达式的const属性;

2.auto使用限制
2.1 auto变量必须初始化;
2.2 auto不能在函数参数中使用;
2.3 auto不能用于类的非静态成员变量;
2.4 auto不能定义数组;
2.5 auto不能作用于模板参数;
2.6 auto遍历STL容器时,修改对象的值不会生效。

3.auto应用场景
3.1 auto用于定义STL中的迭代器;
3.2 auto用于泛型编程(模板类和模板函数等);

4.decltype关键字,与auto功能类似
4.1 decltype(exp) name = value

  • decltype根据表达式exp推导类型,根据表达式的返回类型,但不可以是void;

4.2 如果exp是一个左值,或被()包围,那么decltype((exp))或decltype(n = a+b)的类型就是exp的引用;
4.3 如果exp是一个函数,decltype(exp)并不会执行函数代码。

5.推导类的非静态成员变量或函数返回值类型使用decltype;

template<typename T>
class Base
{
	private:
		decltype(T().begin()) m_iter;
}

6.auto与decltype的区别
6.1 const与volatile,const表示只读,而volatile表示数据易变,简称cv限定符;
6.2 auto可能会去掉cv限定符属性,而decltype则会保留;

7.基于范围的for循环
7.1 遍历

for( auto value : myVector)
{
	//注意:value为myVector中的元素,而不是下标
	...
}
map<string,string> Map;
for(pair<string,string> value :Map)
{
	//map采用pair来遍历
	...
}

7.2 不支持以指针形式返回的数组,只能遍历有明确范围的一组数据,当使用此方法遍历容器时,对某些容器,在遍历过程中动态添加元素会导致出错。

8.基于右值引用的移动语义与完美转发
8.1 通常将可位于赋值号(=)左侧的表达式称为左值,只能位于赋值号右侧的表达式就是右值;
8.2 左值可以作为右值;
8.3 可获取到存储地址的表达式即为左值;
8.4 &只能操作左值,无法添加右值引用,右值引用采用&&来表示;

  • 右值引用必须立即进行初始化,且只能使用右值进行初始化;
int&& a = 10//右值引用可修改,a = 100;

9.移动语义
9.1 用一个对象初始化一个同类对象 -> 复制构造函数;
9.2 移动构造函数,使用右值引用的形式作为函数参数;
9.3 默认情况下,左值初始化同类对象只会调用拷贝构造函数完成,如果想要调用移动构造函数,则必须使用右值进行初始化,为满足这个需求,引入了std::move函数,它可以将左值强制转化为对应的右值,因此而调用移动构造函数;

//移动构造函数写法
Student(Student && stu)
{
	...
}
Student stu;
Student s1 = stu;
Student s2 = std::move(stu);

10.完美转发
10.1 在函数模板中实现参数的完美转发;
10.2 将自己的参数完美的转发给内部调用的其他函数,所谓完美,即不仅能准确的转发参数的值,还能保证被转发的参数的左、右值属性不变;

  • 很多场景是否实现完美转发,直接决定了该参数的传递过程是使用拷贝语义还是移动语义

  • 注意:函数模板,使用右值引用定义参数,是一种万能引用,既可以接收右值,也可以接收左值。

template<typename T>
void function(T&& t)
{
	otherdef(t);
}
//=>折叠引用规则
  • 解决了无论传入的是左值,还是右值,如何在函数内部连同其左,右属性都传入,引入了 f o r w o r d < T > ( ) {forword<T>()} forword<T>();
template<typename T>
void function(T&& t)
{
	otherdef(forword<T>(t));//维护t的左、右属性,实现完美转发。
}

11.nullptr关键字
替代NULL,0等指针复制;

12.智能指针
12.1 share_ptr

#include<memory>
using namespace std;
std::shared_ptr<int> ptr;//引用计数为1;
std::shared_ptr<int> ptr(nullprt);//引用计数为0

//初始化
std::make_shared<T>,有提供拷贝和移动构造函数,同一个普通指针不能为多个shared_ptr赋值;

//自定义释放规则
std::shared_ptr<int> ptr<new int[10],std::default_delete<int[]>());

12.2 unique_ptr

  • 每个unique_ptr指针都独自拥有对其所指堆栈内存空间的所有权,与shared_ptr不同;
  • 只提供移动构造函数;
  • 自定义释放规则;

12.3 weak_ptr

  • 配合shared_ptr使用,不会使引用计数加1或减1,单独使用无意义。

二.std::thread多线程使用心得

1.static_cast ,在编译时进行类型检查,而对于强制转换则不会进行类型检查;

  • 用于基类,子类之间的转换;

2.std::thread_hardware_concurrency(),获取cpu硬件支持的并发数;

3.实现多线程读取文件,每个线程对应一个文件,对多个文件的数据源进行读取,结果汇总。
以下文作者实践后编写的多线程基本框架。

//MultiThread.h及其.cpp文件
#include<queue>
#include <map>
#include<mutex>
#include<thread>
#include<string>

class FileNode
{
public//每个线程执行的函数,主要复则读取file文件,CurrentThreadNumber用于指示当前还没有分配的线程数量,FileNumber指示还有多少文件没有处理,具体实现需要借助m_mutex处理数据,保证m_FileMapData,CurrentThreadNumber,FileNumber数据正确
	void ReadFile(std::string filepath,unsigned int& CurrentThreadNumber,unsigned int& FileNumber);
	//初始化队列
	void InitQuque(std::string dir);
	bool IsQueueEmpty();				//判断队列是否为空,具体实现需要借助m_mutex处理数据,保证数据正确
	bool GetQueueData(std::string file);//获取队列中的数据,具体实现需要借助m_mutex处理数据,保证数据正确
	bool GetQueueSize();				//获取文件总数
private:
	std::mutex m_mutex;											//互斥信号量,用于m_FileQueue和m_FileMapData的线程互斥操作
	std::queue<std::string> m_FileQueue;						//文件处理队列
	std::map<std::string file,std::string data> m_FileMapData;  //数据汇总
};

class MultiThread
{
publicvoid RunMultiThread(unsigned int count,std::string dir);//指定运行的线程数量,dir文需要处理的目录
private:
	FileNode m_Data;
};

void MultiThread::RunMultiThread(unsigned int count,std::string dir)
{
	unsigned int ThreadCount = std::thread_hardware_concurrency() < count ? std::thread_hardware_concurrency() - 1 : count;
	m_Data.InitQuque(dir);//多线程开始前初始化数据
	unsigned int number = m_Data.GetQueueSize();
	while(!m_Data.IsQueueEmpty())
	{
		while(ThreadCount > 0)
		{
			std::string file;
			if(m_Data.GetQueueData(file))
			{
				std::thread th(&FileNode::ReadFile,&m_Data,file,std::ref(ThreadCount),std::ref(number));//ReadFile里面会互斥的修改ThreadCount和number,并通过引用返回结果
				std::mutex mut;
				mut.lock();
				ThreadCount--;//新分配了一个线程,ThreadCount就减少一个,主线程互斥修改
				mut.unlock();
				th.detach();//采用分离式执行子线程,不会阻塞主线程,多线程并行执行
			}
			else break}
	}
	//采用while循环使主线程等待所有子线程执行完毕,保证主线程不会在子线程之前执行完毕而退出
	while(number > 0) continue;
}
#include <iostream>
#include ”MultiThread.h“

int main()

{
	MultiThread MultiTh;
	MultiTh.RunMultiThread(10,"D:\\Data\\");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秘境之眼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值