1.explicit
explicit 用来修饰类的构造函数,如果在类的构造函数前面加了explicit关键字,则在定义类的对象时,不能隐式转换
#include <iostream>
#include <string>
class CInt
{
explicit CInt(int i){}
};
class CStr
{
CStr(std::string str){}
};
CInt ma(1); //ok
CInt mb = 2; //false
CStr mc = "mc"; //ok
2.仿函数
仿函数又称为函数对象,是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,必须重载operator()运算符,好处是方便传参。可以作为算法的方法,也可以作为std::thread的函数
struct func {
func(int i) :m_i(i) { std::cout << "构造函数" << std::endl; }
bool operator()(int a)
{
return a > m_i;
}
int m_i;
};
std::vector<int> vec;
vec.push_back(2);
vec.push_back(8);
std::cout << std::count_if(vec.begin(), vec.end(), func(7)) << std::endl;
3.thread
使用时注意的点
- 调用join等待线程结束的函数时,应该考虑异常的情况,跳过join函数,这样导致该线程无法正常的结束
struct func;
int mi = 0;
func f(mi);
std::thread t(f);
try{
...
}
catch(...){
t.join(); //出现异常时等待结束
throw;
}
t.join(); //正常情况下结束
解决方法一
class thread_guard
{
public:
explicit thread_guard(std::thread& t):m_t(t){}
~thread_guard()
{
if(t.joinable()){
t.join();
}
}
thread_guard(thread_guard& that) = delete;
thread_guard& operator=(thread_guard& that) = delete;
std::thread m_t;
}
std::thread t(f);
thread_guard g(t);
- 类的成员函数作为线程函数
class X
{
public:
void do_something(int);
};
X my_x;
int num = 0;
std::thread t(&X::do_something,&my_x,num);
传入的第三个参数为成员函数的参数,提供的参数可以“移动”,但不能“拷贝”。
移动:原始对象中的数据转移给另一对象,而转移的这些数据就不再在原始对象中保存了。
- 如果不在构造完std::thread后调用join函数,可能会出错,因为有可能主线程已经结束了,子线程还没结束,导致回收资源时出错
- std::thread::hardware_concurrency返回能同时并发在一个程序中的线程数量。
4.lambda函数
意义:
参考某位博主的观点:使用lambda函数,在一些场景下就不必再单独定义一个常规函数,或是一个callable function object(仿函数)
函数的格式:
lambda表达式个人理解,主要用途
1. 用在算法中,如果代码简短,可替代函数指针,例
vector<int> vec;
for(int i = 0;i < 10;;){
vec.push_back(i);
}
for_each(vec.begin(), vec.end(), [](int &n) {if (n % 2) n = -n; });
3. fdjlak
5.function
function是对象,但是是函数指针的作用
- 可以接lambda表达式
std::function<void<int>> f = [](int& n){if(n < 0) n = -n;};
- 可以和bind联合使用
- 待续
6.mutable
- 阻止const对变量修改的限制,一般用在用来修饰成员变量
class C
{
public:
void ModifyData() const
{
i_num = 2; //err
m_str = "world"; //ok
}
private:
int i_num = 1;
mutable std::string m_str = "hello";
};
- 用在lambda函数中
此处对const的用法说明一下
- 修饰形参
void func(const int i);
- 修饰返回值
const int func();
- 修饰成员函数
7.std::ref
c++本身有引用(&),考虑函数式编程在使用时,是对参数直接拷贝,而不是引用,为了使用引用。如果是值传递,则fun修改的是变量的副本。
void fun(int& i){}
void opps()
{
int i = 0;
std::thread t(fun,std::ref(i));//如果不是std::ref(i),传入i,则会报错
}
8.智能指针
在c++11中,智能指针有三个unique_ptr,shared_ptr,weak_ptr
- unique_ptr:同一时刻只能有一个unique_ptr指向给定对象,在多个unique_ptr之间可以使用std::move()进行转移。通过reset方法重新指定,通过release方法释放所有权,通过移动语义转移所有权,没有拷贝语义(使用delete删除了)。
std::unique_ptr<int> uptr(new int(10)); //绑定动态对象
std::unique_ptr<int> uptr2 = std::move(uptr); //轉換所有權
uptr2.release(); //释放所有权
- shared_ptr:多个指针指向相同的对象。shared_ptr使用计数,使用(拷贝和赋值)一次计数加1,每析构一次,内部计数减1。get函数获取原始指针。
int b = 20;
int *pb = &a;
std::shared_ptr<int> ptrb = std::make_shared<int>(b);
pb = ptrb.get(); //获取原始指针
- weak_ptr:对shared_ptr对指针的资源观测。
std::shared_ptr<int> sh_ptr = std::make_shared<int>(10);
std::weak_ptr<int> wp(sh_ptr);
if(!wp.expired()){
std::shared_ptr<int> sh_ptr2 = wp.lock(); //get another shared_ptr
*sh_ptr = 100;
std::cout << wp.use_count() << std::endl;
}
9.std :: accumulate
累计范围内的值.返回将范围中的所有值累加[first,last)到init的结果.
accumulate (InputIterator first, InputIterator last, T init, BinaryOperation binary_op);
std::distance()
返回两个迭代器之间的距离
10.锁
锁有互斥锁(std::mutex)和自旋锁(std::spin_lock)
互斥锁使用场景为操作复杂,时间长,多线程会进行切换
自旋锁使用场景为操作简单,时间短,多线程不会切换
原子操作
将多条指令变成一条不可分割的指令