3.【干货】火爆全网的《超全C++进阶精品教程》C++11新特性(重点)

C++11特性, 智能指针,多线程, bind函数

C++11才有的, 需要添加这个

g++ -g -Wall -std=c++11 main.cpp

 POSIX 标准提供的 实现

RALL是Resource acquisition is initialization的缩写,意思是“资源获取即初始化”,其核心思想是利用C++对象生命周期的概念来控制程序的资源。它的技术原理很简单,如果希望对某个重要资源进行跟踪,那么创建一个对象,并将资源的生命周期和对象的生命周期相关联。这样一来C++自带的对象管理设施就可以来管理资源了

————————————————

http://c.biancheng.net/cplus/11/

C++11 ——— 可变参数模板

分为5类:

1. 智能指针

2. 左值|右值引用(抽象) 

3. 多线程

4. STL库

5. 新增关键字

2011 年,新的 C++ 11 标准诞生,C++ 11 标准无疑是颠覆性的

C++11 最常用的新特性如下:

高优:

右值引用:基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。

智能指针:C++11新增了std::shared_ptr、std::weak_ptr等类型的智能指针,用于解决内存管理的问题。unique_ptr,

新增STL容器array以及tuple

常用: 

线程库:

枚举类:

nullptr关键字:nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型;而NULL一般被宏定义为0,在遇到重载时可能会出现问题。

-------------------------------‘

Lambda 表达式

auto关键字:编译器可以根据初始值自动推导出类型。但是不能用于函数传参以及数组类型的推导。

初始化列表:使用初始化列表来对类进行初始化

atomic原子操作用于多线程资源互斥操作

————————————————

委派和继承构造函数 c++11

继承构造函数的引入原因:如果基类的构造函数很多,那么子类的构造函数想要实现同样多的构造接口,必须一一调用基类的构造函数,有点麻烦

java中的super


classBase{

public:

Base();

Base(intn);

Base(conststring&s);

   ...

};

classDerived:publicBase{

public:

usingBase::Base;// Base's constructors are redeclared here.

};

强类型枚举 C++11

标准C++枚举类型实质上就是整型, 这就存在类型不安全隐患, 同时还存在名字空间冲突的问题. 为此C++11引入了强类型枚举.


// 标准C++枚举

enumSide{

LEFT,

RIGHT,

};

enumThing{

WRONG,

RIGHT,// RIGHT和Side中的RIGHT冲突

};

// C++11 强类型枚举

enumclassSide{

LEFT,

RIGHT,

};

enumclassThing{

WRONG,

RIGHT,// RIGHT和Side中的RIGHT不会冲突

};

C++11显式虚函数重载:override与final

在传统C++中,经常容易发现意外重载虚函数的事情:


structBase{

virtualvoidfoo();

};

structSubClass:Base{

voidfoo();

};

导致有歧义: 用的是父类的, 还是自己重新写了一个

有下列三种场景:

SubClass::foo可能是程序员加入的一个和基类虚函数恰好同名的成员函数,却被编译器当作重载虚函数

SubClass::foo可能是程序员想重载虚函数,但是因为形参列表不同导致编译器认为这是一个新定义的成员函数

当基类的虚函数Base::foo被删除后,SubClass::foo就不再重载该虚函数而摇身一变成为一个普通的成员函数

override

一旦类中的某个函数被声明为虚函数,那么在所有的派生类中它都是虚函数。一个派生类的函数如果覆盖了某个继承而来的虚函数,那么它的形参类型必须与基类函数完全一致。

C++11新标准提供了override关键字来显式地告知虚拟器进行重载,编译器将检查基类是否存在这样的虚函数,否则将无法通过编译。这样的好处是使得程序员的意图更加清晰(覆盖基类中的虚函数),如果我们使用override关键字标记了某个函数但是该函数没有覆盖已有的虚函数,此时编译器会报错。


structBase{

virtualvoidfoo(int);

};

structSubClass:Base{

virtualvoidfoo(int)override;// 合法

virtualvoidfoo(float)override;// 非法, 父类无此虚函数

};

C++11的新特性:

2.2.9 类型推导C++11

推导变量类型-auto

在c++11中,可以使用auto自动推导变量的类型

C++11 中,若变量被声明成 auto, 那它的类型就会被自动匹配成初始化表达式的类型。您可以用 auto 来复制初始化或绑定引用。不过如果使用的不恰当, 会严重影响代码可读性, 所以限制在定义局部变量的范畴.


sparse_hash_map<string,int>::iteratoriter=m.find(val);// 复杂的变量声明

autoiter=m.find(val);// auto的运用可以大幅简化代码

autoi=x.Lookup(key);// 不容易对应的类型, x的声明可能不在附近几行代码中

autox(3);// 圆括号. x的类型是int

autoy{3};// 大括号. y的类型是std::initializer_list<int>

autoz=int{3};// z的类型是int, 不是std::initializer_list<int>

C++ decltype类型推导,decltype 是“declare type”的缩写,译为“声明类型”

既然已经有了 auto 关键字,为什么还需要 decltype 关键字呢?因为 auto 并不适用于所有的自动类型推导场景,在某些特殊情况下 auto 用起来非常不方便,甚至压根无法使用,所以 decltype 关键字也被引入到 C++11 中。

C++返回值类型后置(经常和类型推导&泛型一起用)

2.2.10 列表初始化

C++11中, 任何对象类型都可以被列表初始化, 这提供了一种统一的初始化方式.

在C++11标准中,又对初始化列表的功能进行一次强化

之前是在构造函数中通过列表初始化! 


// Vector 接收了一个初始化列表。

vector<string>v{"foo","bar"};

// 不考虑细节上的微妙差别,大致上相同。

// 您可以任选其一。

vector<string>v={"foo","bar"};

// 可以配合 new 一起用。

autop=newvector<string>{"foo","bar"};

C++11 2.2.11. NULL, nullptr与0

在 C++11 的项目中,建议使用系统关键字 nullptr 代表空指针。 C++11

NULL的本质是一个宏(预处理变量),NULL也代表着0,其导致程序编写存在二义性

举例:


#include<iostream>

usingnamespacestd;

voidfunc(intx)

{

cout<<"void func(int x)"<<endl;

}

voidfunc(int*y)

{

cout<<"void func(int *y)"<<endl;

}

intmain()

{

func(NULL);

return0;

}

上面代码的编写的原意是调用void func(int* x)函数,但结果不尽人意。

由于其本质是((void*)0)和0,NULL看似会隐式类型转换为int*,调用void func(int* y)函数。

但NULL == 0无需隐式类型转换,优先于void func(int* y);。

nullptr_t 是 decltype(nullptr) 的别名,而 nullptr 是一个空指针常量类型,但并没有实际的类型名称。可以保证在任何情况下都代表空指针,并不会代表0。

因为函数重载, 

NULL 宏 替换的是整型的0; nullptr c++关键字。

2.2.11 Lambda 表达式 

lambda匿名函数

C++112.2.12 所有权与智能指针

什么是智能指针

背景: 在C++中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针

概念:  智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动地销毁动态分配的对象,防止内存泄露

原理: 智能指针的核心实现技术是引用计数,每使用它一次,内部引用计数加1,每析构一次内部的引用计数减1,减为0时,删除所指向的堆内存。

C++11中提供了三种智能指针,使用这些智能指针时需要引用头文件<memory>

std::shared_ptr:共享的智能指针

std::weak_ptr:弱引用的智能指针,它不共享指针,不能操作资源,是用来监视shared_ptr的。

std::unique_ptr:独占的智能指针

std::shared_ptr:共享的智能指针的使用:

三步走: 初始化, 获取, 删除器

1). 初始化

ptr1.use_count()

通过调用std::weak_ptr类提供的use_count()方法可以获得当前所观测资源的引用计数

make_shared初始化

reset初始化

2). 使用(setValue(), print() ),通过get()方法得到原始地址! 

   Test* t = ptr5.get();

    t->setValue(1000);

    t->print();

3). 指定删除器

//1.简单举例

    shared_ptr<Test> ppp(new Test(100), [](Test* t) {

        //释放内存

        cout << "Test对象的内存被释放了......." << endl;

        delete t;

        });

独占的智能指针unique_ptr

 1). 初始化

std::unique_ptr是一个独占型的智能指针,它不允许其他的智能指针共享其内部的指针,可以通过它的构造函数初始化一个独占智能指针对象,但是不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr。

 2) . 删除器

unique_ptr指定删除器和shared_ptr指定删除器是有区别的,unique_ptr指定删除器的时候需要确定删除器的类型,所以不能像shared_ptr那样直接指定删除器

具体案例使用: 和共享指针一样, 但是比他简单! 

初始化智能指针unique_ptr.     unique_ptr<int> ptr1(new int(3));

使用:


//1.方法一

unique_ptr<Test>ptr3(newTest(666));

Test*pt=ptr3.get();

pt->setValue(6);

pt->print();

弱引用的智能指针weak_ptr

 弱引用智能指针std::weak_ptr可以看做是shared_ptr的助手,它不管理shared_ptr内部的指针。std::weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,

它的主要作用就是作为一个旁观者监视shared_ptr中管理的资源是否存在。

常用函数

 通过调用std::weak_ptr类提供的expired()方法来判断观测的资源是否已经被释放

通过调用std::weak_ptr类提供的lock()方法来获取管理所监测资源的shared_ptr对象

通过调用std::weak_ptr类提供的reset()方法来清空对象,使其不监测任何资源

————————————————

 C++11 2.2.13 多线程编程  C++11

C++11提供了对多线程的统一支持, 类库更符合C++的习惯, 使用起来更简洁, 不容易出错. C++11明确了内存模型, 但是如果不是对内存模型的行为十分清楚, 则很容易出错, 并且调试起来十分困难, 所以在非必要情况下, 建议使用默认值(std::memory_order_seq_cst).

std::thread是c++11引入标准库的多线程类,std::thread结合lambda,对于实现一些多线程的开发,会变得的更加容易

C++11最重要的特性就是支持了多线程。使得C++在并行编程时不需要依赖第三方库(可以跨平台使用)。并且在原子操作中引入了原子类的概念

thread在向函数传参:引入了一个ref函数来满足这一操作

ref和cref

对于参数传递,我们有时候会需要传递引用,但是跨线程不能直接用引用来传递,需要对参数用ref和cref传递。


threadt1(Func,ref(a));

在C++11中,Mutex共包含了四个互斥量的种类:

互斥量一般都是用作两个线程之间的互斥,一般都是用来保证同一时刻只有一个线程在访问某个变量

(1)mutex

(2)recursive_mutex

(3)time_mutex

(4)recurive_timed_mutex

4者的区别:

 std::recursive_mutex就是在std::mutex的基础上支持了同一个线程多次加锁;std::recursive_timed_mutex就是上面两个的结合体。


std::mutex;// 独占的互斥量,不能递归使用。

std::timed_mutex;// 带超时的独占互斥量,不能递归使用。

std::recursive_mutex;//递归互斥量,不带超时功能。

std::recursive_timed_mutex;//带超时的递归互斥量。

智能锁

例如程序员忘记了解锁或者在加锁期间抛出了异常,那么这个锁就会一直不释放!

这个时候就需要引入c++11的智能锁了,c++11的智能锁充分的利用了c++的RAII机制,完全避免了锁不释放的场景。

lock_guard

lock_guard是C++11中定义的模板类,出作用域前,lock_guard对象要被销毁,调用析构函数自动解锁,可以有效避免死锁的问题。

unique_lock

unique_lock对象销毁时自动调用析构函数解锁,可以方便的防止死锁问题。

与lock_guard不同的是,unique_lock更加的灵活,提供了很多成员函数。

条件变量:  和java中的condition很像!

互斥量主要是用户两个线程之间的互斥,两个线程的同步还是需要使用条件变量。并且条件变量一般都是和互斥量结合使用的

原子操作: atomic

在多线程的场景下,多个线程对同一个变量进行操作,一般情况下都是需要加锁的,但是加锁解锁本身也是有开销的,所以一定程度上会影响性能,那么有没有方法既不需要加锁又可以保证线程安全呢?有!那就是原子变量

总结:

c++11标准库和pthread的对比

优点

接口简洁易用

支持RAII风格的加锁

可以跨平台

配合lambda表达式,可以非常方面的实现多线程的功能

缺点

缺少了一些thread的参数设置,比如优先级、CPU affinity

真实的项目中,很少会直接用thread,更多的是用threadpool. 一般都用线程池! 

2.2.14 可移动类型和可拷贝类型 

移动(move)语义 {通过移动函数初始化 move}

拷贝构造函数又分为浅拷贝和深拷贝:

浅拷贝:当类中有指针时,浅拷贝会发生错误

深拷贝:每次都是重新赋值一份,在某些情况下这种方法可能内存消耗较大

因此就产生了移动构造函数

将原来对象的东西移动到新的对象上

移动后当对象销毁时不能发生错误

移动后原对象不再指向被移动的资源,这些资源的所有权已经归属新创建的对象

move 本意为 "移动",但该函数并不能移动任何数据,它的功能很简单,就是将某个左值强制转化为右值。

在 C++11 的项目中,建议使用系统关键字 nullptr 代表空指针。 C++11

2.2.14 右值引用 C++11

只在两种情况下使用右值引用, 一种是定义类型的移动操作函数时, 另一种是定义模板函数实现完美转发的时候. 除此之外, 不要使用右值引用.

引入右值引用的主要目的是提高程序运行的效率。

有些对象在复制时需要进行深复制,深复制往往非常耗时。合理使用右值引用可以避免没有必要的深复制操作

实际开发中我们可能需要对右值进行修改,为此,C++11 标准新引入了另一种引用方式,称为右值引用,用 "&&" 表示。


int&&a=10;

a=100;

cout<<a<<endl;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容

  • 独占资源的std::unique_ptr     在C++98标准中,智能指针是通过auto_ptr来实现的,但是...
    于天佐阅读 4,068评论 0 0
  • C++11(也称C++2.0、Modern C++) 是继C++98(C++1.0) 之后的第二个国际标准规格,其...
    WalkeR_ZG阅读 10,966评论 0 4
  • lamda表达式 Lambda表达式来源于函数式编程,说白就了就是在使用的地方定义函数,有的语言叫“闭包。如果la...
    ninedreams阅读 362评论 0 0
  • 这篇文章以《C++ Primer》(第五版)为基础,结合自己的理解,将C++11的新特性加以总结、概括,以加深印象...
    toMyLord阅读 834评论 2 6
  • 李亮审稿人:徐方友,邱帅 说起C++语言,它现在被公认为是在各种编程语言中最难学的语言之一,它的语法知识点之广泛,...
    senju阅读 14,576评论 0 1