第一部分:核心语言的特性
一. 右值引用,move语义,完美转发
1. 左值(lvalue)和右值(rvalue)的概念
c++11引入一种新式引用,名曰右值引用,语法:Type&& , const Type&&,区别于之前的&标示的左值引用。为理解右值引用,先要理解左值和右值的概念。
左值,在表达式中,表达式结束时候不会消失,如:obj , *ptr , ptr[index] , ++x
右值,在表达式中,是临时的,表达式结束就会“蒸发”,如:1729 , x + y , std::string("meow") , x++
区分左值和右值,还有另一种方法:能否取得其地址。
如果能取得其地址,是左值,如:&obj , &*ptr , &ptr[index] , &++x是合法的,是左值;
如果不能取得其地址,是右值,如:&1729 , &(x + y) , &std::string("meow") , &x++ 都是不合法的,是右值。
不管是左值还是右值,它要么是modifiable的,要么是const的,如下:
string one("cute");
const string two("fluffy");
string three() { return "kittens"; }
const string four() { return "are an essential part of a healthy diet"; }
one; // modifiable lvalue
two; // const lvalue
three(); // modifiable rvalue
four(); // const rvalue
2. 左值引用和右值引用的绑定特性
左值引用和右值引用各包含modifiable value和const value,故可以分为4种引用形式:
- modifiable lvalue reference
- const lvalue reference
- modifiable rvalue reference
- const rvalue reference
通过上面例子得出的结论:
1) 左值引用和右值引用: modifiable references不能绑定const修饰的值.
2.)右值引用不能绑定左值引用,无论是否const修饰的值.
利用重载函数检查自动绑定:
运行结果:
meow(string&): lvalue
meow(const string&): const_lvalue
meow(string&&): rvalue_func()
meow(const string&&): const_rvalue_func()
请按任意键继续. . .
有个值得注意的地方:当有 const Type& 和 Type&& 重载时,modifiable rvalues bind to Type&&,其他的都bind to const Type&.
3. Move语义
std::move是获得右值的方式,通过move可以将左值转为右值。
运行结果:
After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"
在 C++11,一个std::vector的 "move 构造函数" 对某个vector的右值引用可以单纯地从右值复制其内部 C-style 数组的指针到新的 vector,然后留下空的右值。这个操作不需要数组的复制,而且空的暂时对象的解构也不会摧毁存储器。传回vector暂时对象的函数只需要传回std::vector<T>&&。如果vector没有 move 构造函数,那么复制构造函数将被调用,以const std::vector<T> &的正常形式。 如果它确实有 move 构造函数,那么就会调用 move 构造函数,这能够免除大幅的存储器配置。
二. 类型推导
有被明确初始化的变量可以使用 auto 关键字
使用auto可以减少冗余代码,举例而言,程序员不用写像下面这样:
而可以用更简短的
这里的cbegin()和cend也是c++11新加入的,因为begin(),和end()函数在容器中都有两个,一个返回iterator,
另一个返回const_iterator,因为有auto关键字,编译器将右值推导成哪个不明确,所以对容器内容只读时推荐使用cbegin()和cend()
三. 以范围为基础的 for 循环
for 语句将允许简单的范围迭代:
四. Lambda函数与表示式
在调用C++标准程序库算法函数诸如算法函数诸如sort和find_if时候,第3个参数往往需要输入一个函数对象,既麻烦又冗赘,还好C++11有了Lambda的支持,举例而言,程序员不用写像下面这样:
而可以用Lambda函数代替:
Lambda函数体内需要什么变量,就在方括号中指明,方括号内容的含义:
[] // 沒有定义任何参数。使用未定义参数会导致错误。
[x, &y] // x 以传值方式传入,y 以传引用方式传入。
[&] // 任何被使用到的外部参数皆以引用方式使用。
[=] // 任何被使用到的外部参数皆以传值方式使用。
[&, x] // x 显式地以传值方式加以使用。其余参数以传入方式使用。
[=, &z] // z 显式地以引用方式加以使用。其余参数以传值方式使用。
在成员函数中指涉对象的 this 指针,必须要显式的传入 lambda 函数, 否则成员函数中的 lambda 函数无法使用任何该对象的变量或函数。
[this]() { this->SomePrivateMemberFunction(); };
五. 显示虚函数重载 override final关键字
为防止子类重载的函数与基类函数不一致的情况发生,在编译期期捕获倒错误,语法如下:
C++11也提供关键字final,用来避免类被继承,或是基类的函数被改写:
六. 空指针
C++11 引入了新的关键字来代表空指针常数:nullptr
这部分先介绍到这里,C++11给程序员带来了不少实惠,在这些新特性里我最喜爱的依次是:右值引用,Lambda表达式,auto关键字,虽然现在项目组还在用VS2005开发程序,但我已经迫不及待地自己使用C++11了。
第二部分:标准库的变更
这部分我想简单提一下,具体写出来不是一两遍博客可以完成的,再说也没必要,可以参考cppReference上详细的说明。
1. 线程支持
标准库提供了std::thread,还提供了线程同步的锁(如std::mutex,std::recursive_mutex),可以 RAII 锁 (std::lock_guard 和 std::unique_lock)。
2. 多元组
还记得boost库中的tuple了吗?现在已经引入到了C++11
3. 正则表达式
4. 智能指针
std::shared_ptr不用说了,boost库里有的,unique_ptr我想和boost::scoped_ptr一样使用就行了吧,头文件<memory>
5. 包装引用
std::ref,将值转成引用