常用的C++11特性快速上手

随着时间的发展,C++经历了C++98、C++11、C++14、C++17、C++20等多个标准,特性也越来越多,眼花缭乱的标准和特性让人目不暇接。其实很多最新的标准编译器都还没有支持,只是存在于理论阶段。现在应用的最为广泛的还是C++11标准,这里总结一些C++11中常用的特性,帮助初学者快速入手学习C++11特性。
C++11增加了很多库编写的特性和模板特性,这些特性是针对库开发者和系统开发者的,对普通Coder用处不大。这里主要介绍所有人都能用到的通用特性。
主要分为以下几点:
1.final/override控制
2.列表初始化
3.基于范围的for循环
4.变长模板tuple
5.线程安全的原子类型
6.指针控制nullptr
7. lambda表达式
下面针对各个小点分别进行介绍

1.final/override控制

在继承关系链中,如果在某一层类中,我们的虚函数不想被子类重载,这时候就需要用到final修饰符了,final关键字的作用是使派生类不可覆盖它所修饰的虚函数,final只是在继承关系的“中途”终止派生类的重载中有意义。
如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数。

2.列表初始化

由于引进了列表初始化,我们可以快速的对C++容器进行初始化操作,方便了程序的开发,同时C++列表初始化可以防止类型收窄,在C++11,列表初始化是唯一一种可以防止类型收窄的初始化方式,调用方法如下。

std::vector<int> tempVector = {3,4,5,6,7};
std::list<int> tempList = {3,4,5,6,7};
std::map<int,int> tempMap = {{1:2},{3:4}};

#include <vector>
#include <string>
using namespace std;
在自定义的结构中也可以引入列表初始化的构造函数,方便容器的快速初始化。
enum Gender{boy,girl};
class People{
    public:
        People(initializer_list<pair<string,Gender>> l)
        {
            auto i = l.begin();
            for(;i!=l.end(); ++i)
            data.push_back(*i);
        }
   private:
   vector<pair<string,Gender>> data;     
};
People ship = {{"Garfied",boy},{"HelloKitty",girl}};

3.基于范围的for循环

基于范围的for循环很多人已经使用的很熟练了,这里简单的提一下,通过基于范围的for循环,可以实现C++容器的快速遍历,精简了写法,提升了代码编写的效率。for循环后的括号由冒号:分为两部分,第一部分是范围内用于迭代的变量,第二部分则表示将被迭代的范围。

使用基于范围的for循环有如下要求:
1.for循环迭代的范围是可确定的
2.基于范围的for循环要求迭代的对象实现++和==等操作符。对于标准库中的容器,如string,vector,deque,list,queue,map,set等,不会有问题。
3.标准容器的循环中,使用auto的话将不会是迭代器对象。
使用方法如下:

std::vector<int> tempVector = {1,2,3,4,5,6};
for(int index:tempVector)
{
    std::cout << index;
}

4.变长模板tuple

C++中的pair可以实现一对一的数据对,但当数据量增大的时候pair就束手无策了,这时候就需要用到tuple了。C++11中tuple是pair类的一种更为泛化的表现形式比起pair tuple可以接受任意多个不同类型的元素的集合。

std::tuple<float,char,std::string> mytuple = std::make_tuple(9.8,'g',"gravity");

tuple通过变长模板实现的。

5.线程安全的原子类型和原子操作

所谓原子操作,就是多线程中“最小的且不可并行化的”的操作。
通常对一个共享资源的操作是原子操作的话,意味着多个线程访问该资源时,有且仅有唯一一个线程在对这个资源进行操作。通常情况下原子操作都是通过“互斥”的访问来保证的。实现互斥通常需要平台相关的特殊指令,C++11之前需要在C/C++代码中嵌入内联汇编,粗粒度的互斥,借助POSIX标准的Pthread库中的互斥锁也能做到。
使用原子类型之后就不用显示的加锁。
原子类型包括下面的类型:

atomic_bool;atomic_char;atomic_schar;atomic_uchar;atomic_int;atomic_uint;
atomic_short;atomic_ushort;atomic_long;atomic_ulong;atomic_char16_t;
atomic_char32_t;atomic_wchar_t;

原子类型实现线程安全的Demo:

#include <atomic>
#include <thread>
#include <iostream>
using namespace std;
atomic_llong total{0};
void func(int){
    for(long long i = 0; i<100000000LL; ++i){
        total += i;
    }
}
int main(){
    thread t1(func,0);
    thread t2(func,0);
    t1.join();
    t2.join();
}

6.指针控制nullptr

有些编译器会将NULL解析为0,如果存在函数重载的话会调用对应的int版本。出现该问题的元凶是字面量0的二义性。C++98中字面常量0的类型既可以是一个整型,也可以是一个无类指针(void*)C++11标准中nullptr是一个所谓的“指针空值类型”的常量,指针空值类型被命名为nullptr_t;nullptr是有类型的,且近可以被隐式转换为指针类型。nullptr是一个编译时期的常量,它的名字是一个编译时期的关键字,能够被编译器所识别。
在C++中nullptr到任何指针的转换是隐式的,而(void*)0则必须经过类型转换后才能使用。C++规定用户不能获得nullptr的地址。

7. lambda表达式

lambda表达式的本质在C++中是一个重写了操作符()的类,也被称为仿函数。
仿函数,一般来说,仿函数就是定义了成员函数operator()的一种自定义类型对象。仿函数是编译器实现lambda的一种方式。现阶段,通常编译器会把lambda函数转化成一个仿函数对象。C++11中,lambda可以视为仿函数的一种等价形式。
用户可以使用lambda代替仿函数来书写代码。lambda可以像局部函数一样使用。lambda的类型被定义为“闭包”的类,严格的讲lambda表达式并非函数指针,但C++11允许lambda表达式向函数指针的转换,前提是lambda表达式没有捕捉任何变量,且和函数指针调用方式相同。Lambda 的语法形式如下:

[函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
[capture](parameters)mutable->return-type{statement}
[capture]捕捉列表,出现在最开始处[]是lambda的引出符
(parameters)参数列表,与普通函数的参数列表一致,如果不需要参数传递,可以省略括号
mutable:mutable修饰符,默认lambda函数总是一个const 函数(可设置为mutable)
使用修饰符时参数列表不可省略(即使参数为空)
->return-type:返回类型,不需要返回值的时候可以连同->一起省略,此外在返回类型
明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。
{statement}函数体
[=](int x,int y)const ->int{ return x+y;}

lambda函数可以通过捕捉列表访问一些上下文中的数据,具体的,捕捉列表描述了上下文中哪些数据可以被lambda使用,以及使用方式(以值传递还是以引用传递)
语法上捕捉列表由多个捕捉项目组成,并以逗号分隔,捕捉列表形式如下:
[var]表示值传递方式捕获变量var
[=]表示值传递方式捕捉所有父作用域的变量(包括this)
[&var]引用传递捕捉变量var
[&]表示引用传递捕捉所有父作用域变量(包括this)
[this]表示值传递方式捕捉当前的this指针
父作用域值包含lambda函数的语句块
捕捉列表不逊于变量重复传递如[=,a],[&,&this]
默认值传递会修改报错,引用传递修改则不会报错(修改的是引用的值,而不是引用本身)

这里提炼出一些普通程序员常用的特性供大家参考学习。C++11提出的特性还很多,感兴趣的可以继续深入研究。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农飞飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值