1. 范围for语句
C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素
vector<int> vec = {1,2,3,4,5,6}; for(int x: vec) { cout<<x<<endl; }</div>
2. 尾置返回类型
要想引入尾置类型,我们还得从复杂的类型声明说起。如果我们需要定义一个含有10个int元素的数组,一般是这样的:
int arr[10] = {0};</div>
如果要定义指向这个数组的指针呢:
int (*p_arr)[10] = &arr; //注意:int *p_arr[10] 表示一个数组,有10个元素,元素类型是int*
</div>
如果要定义一个函数,这个函数接受一个char类型的参数,并返回一个指向10个int类型数组的指针呢:
int (*func(char x))[10];
</div>
这样的声明是不是看的头都大了,其实我们可以简化一点,一般情况下我们可以使用别名进行简化,比如:
typedef int ARR[10] ; // 定义一个类型 ARR这是一个数组类型,含有10个int类型的元素
using ARR = int[10] ; // 同上
</div>
再定义如上的函数:
ARR * func(char x) ; // 函数返回的类型是 ARR* 也就是指向具有10个int元素数组的指针
</div>
当然在C++11中我们可以用之前讲到过的另外一个关键字decltype:
decltype(arr) * func(char x) ; // decltype(arr)表达式会获得arr的类型
</div>
最后就轮到我们本节要说的C++11的另外一个特性,尾置返回类型,任何函数都可以使用尾置返回类型,这种形式对于返回类型比较复杂的函数最有效,比如上面的函数可以使用如下方式:
auto func(char x) -> int(*) [10];
</div>
这种形式将函数的返回类型写在函数声明的最后面,并且在函数形参列表后面加上 -> 符号,然后紧接着是函数需要返回的类型,由于函数的返回类型被放在了形参列表之后,所以在函数名前面使用一个 auto替代。
3. =default 生成默认构造函数
在C++的类中,如果我们没有定义构造函数,编译器会为我们合成默认的无参构造函数,如果我们定义了构造函数,则编译器就不生成默认构造函数了,但是如果我们定义构造函数同时也希望编译器生成默认构造函数呢? C++11中可以通过在构造函数的声明中直接 =default的方式要求编译器生成构造函数。
class ClassName{ public: ClassName(int x); ClassName()=default; // 显示要求编译器生成构造函数 };</div>
4. 类对象成员的类内初始化
class ClassName { public: int x = 10; //C++11 之前是不允许的 };</div>
5. lambda表达式与bind函数
lambda表达式是一个可以被调用的代码单元,相当于一个内联函数,有参数和返回值以及函数体。但是跟函数不同的是,lambda表达式可以定义在函数的内部,一个完整的lambda表达式具有如下形式:
[捕获列表](参数列表) mutable -> 返回类型 {函数体}
int x = 10; int y = 20; auto f = [x,&y](int a ,int b){++y;return a+b+x+y;}; cout<<f(1,2)<<endl; //34 cout<<y<<endl; //21</div>
lambda可以省略参数列表(如果没有参数的话),可以省略返回类型,但是不能省略捕获部分与函数体部分,即使捕获列表为空,也要有一个空的[],lambda有两种捕获,一种是值捕获,一种是引用捕获。如果是值捕获那么lambda中获得的是捕获的变量的副本,如果是引用捕获则获得的是引用,可以在lambda内部修改引用的变量的值,如上x是值捕获,y是引用捕获,lambda中默认是值捕获,如果变量前面添加&则是引用捕获,另外lambda中还有两种形式的引用捕获,例如[=]表示值捕获所有可见的变量,而[&]则表示引用捕获所有可见变量。如果希望值捕获所有可见变量,但是又有个别变量采用引用捕获呢,[=,&x]表示值捕获所有可见变量,同时引用捕获x。而[&,x]则表示引用捕获所有可见变量,x采用值捕获的方式。
有关bind函数,在很多地方我们可以使用函数替换lambda表达式,毕竟如果很多地方需要用到同一个lambda表达式,而且这个lambda表达式比较长的话,将其定义成函数应该是最好的。对于没有捕获列表的lambda表达式我们可以直接使用函数替代,例如:
void main() { auto f=[](int x,int y){return x+y}; f(); }</div>
我们可以用下面的方式替代:
int f(int x,int y) { return x+y; } void main() { f(); }</div>
与上面的lambda是等价的,但是对于有捕获列表的lambda表达式应该怎么处理呢,例如:
void main() { int x = 10; int y = 20; auto f = [x,&y](int a ,int b){return a+b+x+y;}; //一个值捕获,一个引用捕获 f(33,44); }</div>
如果转换成函数的形式:
int x = 10; int y = 20; int f(int a,int b) { return a+bx+y; } void main() { f(33,44); }</div>
这是一种可行的方法,但是总不能把所有的捕获变量定义成全局变量吧。现在的关键问题是lambda的捕获表达式中的内容转换成函数不可行,C++11提供了bind函数来完成这样的操作。
#include <functional> //bind() #include <iostream> using namespace std; using namespace std::placeholders; // _1,_2所在的命名空间 int f(int x,int y,int a,int b) { return a+b+x+y; } void main() { int x = 10; int y = 20; auto f_wrap = bind(f,x,y,_1,_2); cout<<f_wrap(33,44)<<endl; // _1,_2是占位符,表示调用f_wrap的时候_1是第一个参数,_2是第二个参数。最终会被替换成调用 f(10,20,33,44) }</div>
如果引用类型的捕获怎么做呢,看下面的例子,用lambda是这样的:
#include <iostream> #include <functional> using namespace std; using namespace std::placeholders; void main() { int x = 10; ostream &o = cout; auto f =[&o](int a){o<<a<<endl;}; // 注意这里的输出对象是用的引用捕获 f(x); }</div>
使用bind是这样的:
#include <iostream> #include <functional> using namespace std; using namespace std::placeholders; void f(ostream &o,int x) { o<<x<<endl; } int main() { int x = 10; auto f_wrap = bind(f,ref(cout),_1); //将变量的引用传递到bind中是个问题,为此C++11提供了ref()函数用于获得引用 f_wrap(x); return 0 ; }</div>
6. 智能指针share_ptr,unique_ptr
C++11中引入了几种智能指针,智能指针能够自动释放所指向的对象,其中shared_ptr允许多个指针指向同一个对象,unique_ptr则独占所指向的对象,我们主要说明shared_ptr的使用。通过使用m