一 .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);
}
//=>折叠引用规则
- 解决了无论传入的是左值,还是右值,如何在函数内部连同其左,右属性都传入,引入了forword<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
{
public:void 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;
}