C语言也有auto关键字,但是其含义只是与static变量做一个区分,一个变量不指定的话默认就是auto。因为很少有人去用这个东西,所以在C++11中就把原有的auto功能给废弃掉了,而变成了现在的自动类型推导关键字。用法很简单不多赘述,比如写一个auto a = 3, 编译器就会自动推导a的类型为int. 在遍历某些STL容器的时候,不用去声明那些迭代器的类型,也不用去使用typedef就能很简洁的实现遍历了。
auto的使用有以下两点必须注意:
lambda表达式是匿名函数,可以认为是一个可执行体functor,语法规则为[捕获区](参数区){代码区};
如:
auto add = [](int a, int b) {return a + b};
就我的理解而言,捕获的意思即为将一些变量展开使得为lambda内部可见,具体方式有如下几种
[a,&b] 其中 a 以复制捕获而 b 以引用捕获。
[this] 以引用捕获当前对象( *this )
[&] 以引用捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在
[=] 以复制捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在
[] 不捕获,大部分情况下不捕获就可以了
lambda一般使用场景为:sort等自定义比较函数、用thread起简单的线程。
右值引用是C++11新特性,它实现了转移语义和完美转发,主要目的有两个方面
C++中的变量要么是左值、要么是右值。通俗的左值定义指的是非临时变量,而左值指的是临时对象。左值引用的符号是一个&,右值引用是两个&&。
转移语义可以将资源(堆、系统对象等)从一个对象转移到另一个对象,这样可以减少不必要的临时对象的创建、拷贝及销毁。移动语义与拷贝语义是相对的,可以类比文件的剪切和拷贝。在现有的C++机制中,自定义的类要实现转移语义,需要定义移动构造函数,还可以定义转移赋值操作符。
以string类的移动构造函数为例:
MyString(MyString&& str) {
std::cout << "Move Ctor source from " << str._data << endl;
_len = str._len;
_data = str._data;
str._len = 0;
str._data = NULL;
}
和拷贝构造函数类似,有几点需要注意:
标准库函数std::move 可以将左值变成一个右值。
编译器只对右值引用才能调用移动构造函数,那么如果已知一个命名对象不再被使用,此时仍然想调用它的移动构造函数,也就是把一个左值引用当做右值引用来使用,该怎么做呢?用std::move,这个函数以非常简单的方式将左值引用转换为右值引用。
核心思想:为防止内存泄露等问题,用一个对象来管理野指针,使得在该对象构造时获得该指针管理权,析构时自动释放(delete).
基于此思想C++98提供了第一个智能指针:auto_ptr。
auto_ptr基于所有权转移的语义,即将一个就的auto_ptr赋值给另外一个新的auto_ptr时,旧的那一个就不再拥有该指针的控制权(内部指针被赋值为null),那么这就会带来一些根本性的破绽:
因为auto_ptr的各种bug,C++11标准基本废弃了这种类型的智能指针,转而带来了三种全新的智能指针:
这里给出一个shared_ptr的简单实现:
class Counter {
friend class SmartPointPro;
public:
Counter(){
ptr = NULL;
cnt = 0;
}
Counter(Object* p){
ptr = p;
cnt = 1;
}
~Counter(){
delete ptr;
}
private:
Object* ptr;
int cnt;
};
class SmartPointPro {
public:
SmartPointerPro(Object* p){
ptr_counter = new Counter(p);
}
SmartPointerPro(const SmartPointerPro &sp){
ptr_counter = sp.ptr_counter;
++ptr_counter->cnt;
}
SmartPointerPro& operator=(const SmartPointerPro &sp){
++sp.ptr_counter->cnt;
--ptr_counter.cnt;
if(ptr_counter.cnt == 0)
delete ptr_counter;
ptr_counter = sp.ptr_counter;
}
~SmartPointerPro(){
--ptr_counter->cnt;
if(ptr_counter.cnt == 0)
delete ptr_counter;
}
private:
Counter *ptr_counter;
};
需要记住的事,在以下三种情况下会引起引用计数的变更:
std::thread可以和普通函数和lambda表达式搭配使用。它还允许向线程执行函数传递任意多参数。
#include
void func() {
// do some work here
}
int main() {
std::thread thr(func);
t.join();
return 0;
}
上面就是一个最简单的使用std::thread的例子,函数func()在新起的线程中执行。调用join()函数是为了阻塞主线程,直到这个新起的线程执行完毕。线程函数的返回值都会被忽略,但线程函数可以接受任意数目的输入参数。
std::thread的其他成员函数:
除了std::thread的成员函数外,在std::this_thread命名空间也定义了一系列函数用于管理当前线程:
get_id:返回当前线程的id
yield:告知调度器运行其他线程,可用于当前处于繁忙的等待状态。相当于主动让出剩下的执行时间,具体的调度算法取决于实现
sleep_for:指定的一段时间内停止当前线程的执行
sleep_until:停止当前线程的执行直到指定的时间点