C++11新特性介绍

fushilin 2020-05-28

C++是学习SLAM不可缺少的一环,正确的使用新特性能极大地提高学习效率,本文介绍C++11的新特性

C++11

C++11是曾经被叫做C++0x,是对目前C++语言的扩展和修正,C++11不仅包含核心语言的新
机能,而且扩展了C++的标准程序库(STL),并入了大部分的C++ Technical Report
1(TR1)程序库(数学的特殊函数除外)。
C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto、decltype,和模板的大
量改进。
本文将对C++11的以上新特性进行简单的讲解,以便大家能够快速了解到C++11对C++的易用
性方面祈祷的巨大作用。

C++11重要新特性

1. 自动类型推导

auto

C++11中引入auto第一种作用是为了自动类型推导。
auto的自动类型推导,用于从初始化表达式中推断出变量的数据类型。通过auto的自动类型推
导,可以大大简化我们的编程工作。
auto实际上在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响,另外,似乎auto并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配。

decltype

decltype实际上有点像auto的反函数,auto可以让你声明一个变量,而decltype则可以从一个
变量或表达式中得到类型,有实例如下:

int x = 3;
decltype(x) y = x;

有人会问,decltype的实用之处在哪里呢,我们接着上边的例子继续说下去,如果上文中的加
工产品的例子中我们想把产品作为返回值该怎么办呢?我们可以这样写:

template <typename Creator>
auto processProduct(const Creator& creator) ->
decltype(creator.makeObject()) {
auto val = creator.makeObject();
// do somthing with val
}

2. 区间迭代:基于范围的 for 循环

在C++中for循环可以使用类似java的简化的for循环,可以用于遍历数组,容器,string以及由
begin和end函数定义的序列(即有Iterator),示例代码如下:

map<string, int> m{{"a", 1}, {"b", 2}, {"c", 3}};
for (auto p : m){
cout<<p.first<<" : "<<p.second<<endl;
}

3. Lambda表达式

lambda表达式类似Javascript中的闭包,它可以用于创建并定义匿名的函数对象,以简化编程
工作。lambda提供了一个类似匿名函数的特性,而匿名函数则是在需要一个函数,但是又不想费力去命名一个函数的情况下去使用的。
Lambda的语法如下:
[函数对象参数](操作符重载函数参数)->返回值类型{函数体}

vector<int> iv{5, 4, 3, 2, 1};
int a = 2, b = 1;
for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;}); // (1)
for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);}); // (2)
for_each(iv.begin(), iv.end(), [=](int &x)->int{return x * (a + b);});//
(3)

[]内的参数指的是Lambda表达式可以取得的全局变量。(1)函数中的b就是指函数可以得
到在Lambda表达式外的全局变量,如果在[]中传入=的话,即是可以取得所有的外部变
量,如(2)和(3)Lambda表达式()内的参数是每次调用函数时传入的参数。->后加上的是Lambda表达式返回值的类型,如(3)中返回了一个int类型的变量

4. 初始化列表

在引入C++11之前,只有数组能使用初始化列表,其他容器想要使用初始化列表,只能用以下
方法:

int arr[3] = {1, 2, 3}
vector<int> v(arr, arr + 3);
在C++11中,我们可以使用以下语法来进行替换:
int arr[3]{1, 2, 3};
vector<int> iv{1, 2, 3};
map<int, string>{{1, "a"}, {2, "b"}};
string str{"Hello World"};

5. 正则表达式

C++11 提供的正则表达式库操作 std::string 对象,对模式 std::regex (本质是 std::basic_regex)进行初始化,通过 std::regex_match 进行匹配,从而产生 std::smatch (本质是 std::match_results 对象)。

6. 新增容器

std::array 保存在栈内存中,相比堆内存中的 std::vector,我们能够灵活的访问这里面的元素,从而获得更高的性能。

7. nullptr

nullptr是为了解决原来C++中NULL的二义性问题而引进的一种新的类型,因为NULL实际上代
表的是0,

8. 构造函数

C++11 引入了委托构造的概念,这使得构造函数可以在同一个类中一个构造函数调用另一个构造函数,从而达到简化代码的目的。

9. 模板增强

扩充了原来的强制编译器在特定位置实例化模板的语法,使得**能够显式的告诉编译器何时进行模板的实例化
我们在C++中都用过pair,pair可以使用make_pair构造,构造一个包含两种不同类型的数据的
容器。比如,如下代码:

auto p = make_pair(1, "C++ 11");

由于在C++11中引入了变长参数模板,所以发明了新的数据类型:tuple,tuple是一个N元组,
可以传入1个, 2个甚至多个不同类型的数据

auto t1 = make_tuple(1, 2.0, "C++ 11");
auto t2 = make_tuple(1, 2.0, "C++ 11", {1, 0, 2});

这样就避免了从前的pair中嵌套pair的丑陋做法,使得代码更加整洁
另一个经常见到的例子是Print函数,在C语言中printf可以传入多个参数,在C++11中,我们可
以用变长参数模板实现更简洁的Print

template<typename head, typename... tail>
void Print(Head head, typename... tail) {
cout<< head <<endl;
Print(tail...);
}

Print中可以传入多个不同种类的参数,如下:

Print(1, 1.0, "C++11");

10. 语言级线程支持

代码编译需要使用 -pthread 选项

std::thread
std::mutex/std::unique_lock
std::future/std::packaged_task
std::condition_variable

11. 右值引用和move语义

通过重载直接使用右值参数。我们所要做的就是写一个以右值引用为参数的构造函数:

举例 熟悉C++11

题目描述

? C++ 是一门古老的语言,但它的标准至今仍在不断发展。在 2011 年、2014 年和 2017 年,C++ 的标准又进行了更新,被称为 C++11,C++14,C++17。其中,C++11 标准是最重要的一次更新,让 C++ 发生了重要的改变,也使得近年来的 C++ 程序与你在课本上(比如谭浩强)学到的 C++ 程序有很大的不同。你甚至会惊叹这是一种全新的语言。C++14 和 C++17 则是对 11 标准的完善与扩充。
? 越来越多的程序开始使用 11 标准,它也会让你在写程序时更加得心应手。本题中,你将学习一些 11标准下的新语法。请参考本次作业 books/目录下的两个 pdf,并回答下面的问题。
? 设有类 A,并有 A 类的一组对象,组成了一个 vector。现在希望对这个 vector 进行排序,但排序的方式由 A.index 成员大小定义。那么,在 C++11 的语法下,程序写成:

#include <iostream> 
#include <vector> 
#include <algorithm>

using namespace std;

class A {
public:
    A(const int& i ) : index(i) {};
    int index = 0;
};

int main() {
    A a1(3), a2(5), a3(9);
    vector<A> avec{a1, a2, a3};
    std::sort(avec.begin(), avec.end(), [](const A&a1, const A&a2) {return a1.index<a2.index;}); 
    for ( auto& a: avec ) cout<<a.index<<" ";
    cout<<endl;
    return 0;
}

请说明该程序中哪些地方用到了 C++11 标准的内容。提示:请关注范围 for 循环、自动类型推导、lambda表达式等内容。

答:

第9行:使用了初始化列表来初始化字段;

A(const int& i ) : index(i) {};

等同于以下字段

A(const int& i )
{
    index = i;
}

第15行:使用了初始化列表来初始化对象: C++11 把初始化列表的概念绑定到了类型上,并将其称之为 std::initializer_list,允许构造函数或其他函数像参数一样使用初始化列表,这就为类对象的初始化与普通数组和 POD 的初始化方法提供了统一的桥梁。

第16行:使用了lambda表达式来比较元素大小,其中:const A&a1, const A&a2是参数列表,return a1.index<a2.index;是函数体,返回值是布尔型的大小比较结果。

第17行:用auto关键字实现了自动类型推导,让编译器自动设置变量a的类型;

第17行:C++引入了基于范围的for循环,不用下标就能访问元素;

相关推荐