一、新语法

1.自动类型推导auto

auto的自动推导,用于从初始化表达式中推断出变量的数据类型。

//C++98
int a = 10;
string s = "abc";
float b = 10.0;
vector<int> c;
vector<vector<int> > d;
map<int, string> m;
m[1] = "aaa";
map<int, string>::iterator it = m.begin();//C++11
auto a1 = 10;  //a1为int
auto s1 = "abc";  //s1为string
auto b1 = b;
auto c1 = c;
auto d1 = d;
auto e1 = 'a';
int* x = &a1;
auto d1 = x;
auto m1 = m.begin();
auto x=1,y=2; //ok
auto i=1.j=3.14; //compile errordouble a2 = 3.144;
const auto a3 = a2;  //const double
auto a4 = a2;  //double
volatile int c2 = 3;
auto c3 = c2; //int

2.萃取类型decltype

decltype可以通过一个变量或表达式得到类型。

#include <iostream>
#include <vector>using namespace std;int add(int a)
{return ++a;
}void fun(int a)
{cout << "call function: [int]\n" << endl;
}void fun(int *a)
{cout << "call function: [int*]\n" << endl;
}int main()
{//C++11int aa = 10;decltype(aa) bb = 11;string ss = "hello intel";decltype(ss) ss1 = "hello";const vector<int> vec(1);decltype(vec[0]) cc = 1;decltype(0) dd = vec[0];  //dd是int类型decltype(add(1)) ee;  //intint a[5];decltype(a) ff; //int[5]//decltype(fun) gg;  无法通过编译,是个重载函数return 0;
}

3.nullptr

空指针标识符nullptr是一个表示空指针的标识,他不是一个整数,这是与我们常用的NULL宏的区别。NULL只是一个定义为常整数0的宏,而nullptr是C++11的一个关键字,一个內建的标识符。

#include <iostream>
#include <vector>using namespace std;void fun(int a)
{cout << "call function: [int]\n" << endl;
}void fun(int *a)
{cout << "call function: [int*]\n" << endl;
}int main()
{//C++11fun(NULL);   //call function: [int]fun(nullptr);  //call function: [int*]int* p = NULL;fun(p);  //call function: [int*]return 0;
}

4.区间迭代range for

C++98C++11在使用语法上的差异如下:

#include <iostream>
#include <vector>using namespace std;int main()
{//C++98vector<int> vec(8, 1);cout << "C++98 range for:" << endl;for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++){cout << *it << endl;}//C++11cout << "C++11 range for:" << endl;for (auto d : vec){cout << d << endl;}return 0;
}

值得指出的是,是否能够使用基于范围的for循环,必须依赖一些条件。首先,就是for循环迭代的范围是可确定的。对于类来说,如果该类有begin和end函数,那么for_each之间就是for循环迭代的范围。对于数组而言,就是数组的第一个和最后一个元素间的范围。其次,基于范围的for循环还要求迭代的对象实现+ + 和==等操作符。对于STL中的容器,如string、array、map等使用起来是不会有问题的。下面是C++11操作vector和数组的实践:

#include <vector>using namespace std;int main()
{vector<int> vec(8, 1);//C++11cout << "C++11 value range for:" << endl;/*d非引用,修改d不会影响vector里的值*/for (auto d : vec)   //d中存储的是vec中的值{d = 2;}for (auto d : vec)   {cout << d << endl;}cout << "C++11 reference range for:" << endl;/*当迭代变量d为引用时,vector里的值可以被修改*/for (auto &d : vec)  {d = 2;}for (auto d : vec)   {cout << d << endl;}//数组for_eachchar arr[] = {'a','b','c','d'};for (auto &d : arr){d -= 32;}for (auto d : arr){cout << d << endl;}//遍历二维数组,注意迭代变量row必须为引用。如果你想用 range for 的方法,来遍历更高维的数组 (dim > 2),//那么你只需要:除了最内层循环之外,其他所有外层循环都加入 '&' 即可。int array2[5][5] = {0};for (auto &row : array2)for (auto col : row)cout << col << endl;return 0;
}

5.返回类型后置语法

先看下面这个例子,编译器在推导decltype(t1+t2)时表达式中t1和t2都未声明,所以编译失败。

#include <iostream>
#include <vector>using namespace std;template<class T1, class T2>
decltype(t1 + t2) sum(T1 t1, T2 t2)
{return t1 + t2;
}int main()
{auto total = sum(1, 2);cout << total << endl;return 0;
}

所以C++11引入新语法,即把函数的返回值移至参数声明之后,复合符号->decltype(t1+t2)被称为追踪返回类型。而原本的函数返回值由auto占据。

#include <iostream>
#include <vector>using namespace std;template<class T1, class T2>
auto sum(T1 t1, T2 t2) ->decltype(t1+t2)
{return t1 + t2;
}int main()
{auto total = sum(1, 2);cout << total << endl;return 0;
}

6.final和override

struct B
{virtual void f1(int) const;virtual void f2();void f3();
};struct D1 : public B
{void f1(int) const override;  //okvoid f2(int) override;   //error,B中没有形如f2(int)的函数void f3() override;  //error,f3不是虚函数void f4() override;  //error,B中无f4函数
};struct D2 : public B
{void f1(int) const final;  //不许后续的其他类覆盖
};struct D3 :public D2
{void f2();void f1(int) const; //error,final函数不可覆盖
};

final还可以用于防止继承的发生:

class NoDerived final
{};class Bad :NoDerived   //NoDerived不可做基类
{};class Base
{};class Last final :Base
{};class Bad2 :Last   //Last不可做基类
{};

7.=default和=delete

对于 C++ 的类,如果程序员没有为其定义特殊成员函数,那么在需要用到某个特殊成员函数的时候,编译器会隐式的自动生成一个默认的特殊成员函数,比如拷贝构造函数,或者拷贝赋值操作符。

C++11允许我们使用=default来要求编译器生成一个默认构造函数,也允许我们使用=delete来告诉编译器不要为我们生成某个默认函数。

class B
{B() = default; //显示声明使用默认构造函数B(const B&) = delete; //禁止使用类对象之间的拷贝~B() = default;  //显示声明使用默认析构函数B& operator=(const B&) = delete;  //禁止使用类对象之间的赋值B(int a);
};

8.lambda表达式

简单来说,Lambda函数也就是一个函数(匿名函数),它的语法定义如下:

[capture](parameters) mutable ->return-type{statement}

  1. [=,&a,&b]表示以引用传递的方式捕捉变量a和b,以值传递方式捕捉其它所有变量;
  2. [&,a,this]表示以值传递的方式捕捉变量a和类的this指针,引用传递方式捕捉其它所有变量。
#include <iostream>using namespace std;int main()
{auto f = []() {cout << "hello world!" << endl; };f();  //hello world!int a = 123;auto f1 = [a] { cout << a << endl; };f1();  //123auto f2 = [&a] {cout << a << endl; };a = 789;f2();  //789//隐式捕获:让编译器根据函数体中的代码来推断需要捕获哪些变量auto f3 = [=] {cout << a << endl; };f3();  //789auto f4 = [&] {cout << a << endl; };a = 990;f4();  //990auto f5 = [](int a, int b)->int {return a + b; };printf("%d\n", f5(1, 2));  //3return 0;
}

lambda表达式在C++下的应用,排序

#include <stdio.h>
#include <algorithm>
#include <vector>using namespace std;void print(char arr[], int len)
{for (int i = 0; i < len; i++){printf("%d ", arr[i]);}printf("\n");
}bool cmp(char a, char b)
{if (a > b)return true;elsereturn false;
}int main()
{//c++98char arr1[] = { 2,5,2,1,5,89,36,22,89 };int len = sizeof(arr1) / sizeof(char);sort(arr1, arr1 + len, cmp);print(arr1, len);//c++11char arr2[] = { 2,5,2,1,5,89,36,22,89 };int len2 = sizeof(arr2) / sizeof(char);sort(arr2, arr2 + len2, [](char a, char b)->bool {return a > b; });print(arr2, len2);return 0;
}

9.std::move

std::move是为性能而生,通过std::move,可以避免不必要的拷贝操作。std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。

#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{std::string str = "Hello";std::vector<std::string> v;//调用常规的拷贝构造函数,新建字符数组,拷贝数据v.push_back(str);std::cout << "After copy, str is \"" << str << "\"\n"; //After move, str is "Hello"//调用移动构造函数,掏空str,掏空后,最好不要使用strv.push_back(std::move(str));std::cout << "After move, str is \"" << str << "\"\n";   //After move, str is ""std::cout << "The contents of the vector are \"" << v[0]<< "\", \"" << v[1] << "\"\n";   //The contents of the vector are "Hello", "Hello"
}

二、STL新内容

1.std::array

  1. 使用 std::array保存在栈内存中,相比堆内存中的 std::vector,我们就能够灵活的访问这里面的元素,从而获得更高的性能;同时正式由于其堆内存存储的特性,有些时候我们还需要自己负责释放这些资源。

  2. 使用std::array能够让代码变得更加现代,且封装了一些操作函数,同时还能够友好的使用标准库中的容器算法等等,比如 std::sort。

std::array 会在编译时创建一个固定大小的数组,std::array 不能够被隐式的转换成指针,使用 std::array 很简单,只需指定其类型和大小即可:

#include <stdio.h>
#include <algorithm>
#include <array>void foo(int* p)
{}int main()
{std::array<int, 4> arr = {4,3,1,2};foo(&arr[0]);  //OKfoo(arr.data());  //OK//foo(arr);  //wrongstd::sort(arr.begin(), arr.end());  //排序return 0;
}

2.std::forward_list

std::forward_list 使用单向链表进行实现,提供了 O(1) 复杂度的元素插入,不支持快速随机访问(这也是链表的特点),也是标准库容器中唯一一个不提供 size() 方法的容器。当不需要双向迭代时,具有比 std::list 更高的空间利用率。

#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <forward_list>int main()
{std::forward_list<int> list1 = { 1, 2, 3, 4 };//从前面向foo1容器中添加数据,注意不支持push_backlist1.pop_front();  //删除链表第一个元素list1.remove(3);   //删除链表值为3的节点list1.push_front(2);list1.push_front(1);list1.push_front(14);list1.push_front(17);list1.sort();for (auto &n : list1){if (n == 17)n = 19;}for (const auto &n : list1){std::cout << n << std::endl;  //1 2 2 4 14 19}return 0;
}

3.std::unordered_map和std::unordered_set

无序容器中的元素是不进行排序的,内部通过 Hash 表实现,插入和搜索元素的平均复杂度为 O(constant),在不关心容器内部元素顺序时,能够获得显著的性能提升。

C++11 引入了两组无序容器:std::unordered_map/std::unordered_multimap 和 std::unordered_set/std::unordered_multiset。

下面给出unordered_map和unordered_set的使用方法。

#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>void foo(int* p)
{}int main()
{//unordered_map usagestd::unordered_map<std::string, int> um = { {"2",2},{"1",1},{"3",3} };//遍历for (const auto &n : um){std::cout << "key:" << n.first << "  value:" << n.second << std::endl;}std::cout << "value:" << um["1"] << std::endl;//unordered_set usagestd::unordered_set<int> us = { 2,3,4,1};//遍历for (const auto &n : us){std::cout << "value:" << n << std::endl;}std::cout << "value:" << us.count(9) << std::endl; //判断一个数是否在集合内,1存在0不存在std::cout << "value:" << *us.find(1) << std::endl;  //查找一个特定的数是否在集合内,找到就返回该数的迭代器位置return 0;
}

三、智能指针

1. std::shared_ptr

shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引用计数是安全的,但是对象的读取需要加锁。

#include <stdio.h>
#include <memory>
#include <iostream>int main()
{//auto ptr = std::make_shared<int>(10);std::shared_ptr<int> ptr(new int(10));std::shared_ptr<int> ptrC(ptr);auto ptr2 = ptr;{auto ptr3 = ptr2;std::cout << "pointer1.use_count() = " << ptr.use_count() << std::endl;  //4std::cout << "pointer2.use_count() = " << ptr2.use_count() << std::endl;  //4}std::cout << "pointer1.use_count() = " << ptr.use_count() << std::endl;  //3std::cout << "pointer2.use_count() = " << ptr2.use_count() << std::endl;  //3int *p = ptr.get(); //获取原始指针std::cout << "pointer1.use_count() = " << ptr.use_count() << std::endl;  //3std::cout << "pointer2.use_count() = " << ptr2.use_count() << std::endl;  //3return 0;
}

2. std::unique_ptr

std::unique_ptr 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象,从而保证代码的安全:

#include <stdio.h>
#include <memory>
#include <iostream>int main()
{std::unique_ptr<int> ptr(new int(10));//auto ptr2 = ptr; //非法//虽说unique_ptr是不可复制的,但我们可以使用std::move将其独占权转移到其他的unique_ptrauto ptr2(std::move(ptr));std::cout << *ptr2 << std::endl;return 0;
}

3. std::weak_ptr

先观察下面的代码,如果我们在类father中使用的是shared_ptr,就是shared_ptr的环形引用问题。

#include <iostream>
#include <memory>
using namespace std;class father;
class son;class father {
public:father() {cout << "father !" << endl;}~father() {cout << "~~~~~father !" << endl;}void setSon(shared_ptr<son> s) {son = s;}
private://shared_ptr<son> son;weak_ptr<son> son; // 用weak_ptr来替换
};class son {
public:son() {cout << "son !" << endl;}~son() {cout << "~~~~~~son !" << endl;}void setFather(shared_ptr<father> f) {father = f;}
private:shared_ptr<father> father;
};void test() {shared_ptr<father> f(new father());shared_ptr<son> s(new son());f->setSon(s);s->setFather(f);
}int main()
{test();return 0;
}

为了避免shared_ptr的环形引用问题,需要引入一个弱引用weak_ptr, weak_ptr是为了配合shared_ptr而引入的一种智能指针,弱引用不会引起引用计数增加,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。

输出:

father !
son !
~~~~~~son !
~~~~~father !

转自:在C++98基础上学习C++11新特性

这个博主写的很多东西都是精品,可以多看看。

【C/C++】C++98基础上的C++11新特性相关推荐

  1. java9特性_96.java基础10(java9/10/11新特性)

    126.java 9 新特性1(模块化功能): 1.java模块化 2.java 交互式环境jshell 3.泛型 package com.atguigu.java; import org.junit ...

  2. C++ C++基础语法入门总结(二)引用-内联函数-C++11新特性

    C++基础语法入门总结 C++引用 再谈引用和指针 C++内联函数 附加C++11新特性 auto关键字 基于范围的for循环 指针空值nullptr C++引用 引用:就是某一变量(目标)的一个别名 ...

  3. 7.Java基础之集合框架+JDK8新特性

    1.集合概述 1.1 为什么学集合 思考:数组有什么缺点? 长度一旦定义,不能改变!定义大了,浪费空间:小了,可能不够 ---->动态的数组 对于增删,需要移动位置 ->有人帮我们做这个事 ...

  4. Java基础笔记-Java8及其他新特性

    第十六章 Java8及其他新特性 16.1 Java8新特性简介 16.2 lambda表达式和函数式接口 16.3 方法引用与构造器引用 16.4 StreamAPI的使用 16.5 Optiona ...

  5. 安卓9.0发布,献上Android 9.0新特性适配处理

    安卓9.0即Android 9.0已经面向全球发布,它的代号是Pie,仍然基于Linux内核构建.为了避免Android 9.0 Pie新特性更新引发的适配问题,本文将介绍Android 9.0将带来 ...

  6. HTML基础(一)--HTML5新特性和语义化

    一.语义化概念 HTML5的语义化指的是合理正确的使用语义化标签来创建页面标签,正确的标签做正确的事,有利于SEO 二.语义化标签 header .nav.main(文档的主体).arcticle.s ...

  7. 前端面试html5新特性,前端面试基础-html篇之H5新特性

    h用能境战求道,重件开又是正易里是了些之框5的新特性(目前个人所了解)如求圈分件圈浏第用代是水刚道.的它还下 语义化标签 表单新特性 视频(vi朋不功事做时次功好来多这开制的请一例农在deo)和音频( ...

  8. Google I/O 2019上提及的Javascript新特性

    使用#来定义私有属性 #count 是私有变量,不能通过 IncreasingCounter 实例访问 class IncreasingCounter {#count = 0;get value(){ ...

  9. 黑马程序员---基础加强-----------------第二天(新特性:注解、泛型)

    注解:相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记. 以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记, ...

最新文章

  1. html 多项选择,选项标签中的HTML多字段选择
  2. Oracle事务和常用数据库对象
  3. slack 国内 android,使用Slack Api登录,Android
  4. Python爬取js动态添加的内容
  5. loadrunner 关联匹配多个值
  6. addroid 自定义布局
  7. 不停机与停机更新_Istio的零停机滚动更新
  8. Python -- sys模块
  9. 蓝桥杯 ALGO-26 算法训练 麦森数
  10. OpenCV-膨胀cv::dilate
  11. 是否可以改变 宏的值_宋轶白成一道光??抓住美白季你也可以
  12. 微信小程序体验版无法调用接口
  13. 图片裁剪源代码+php,php进行图片裁剪及生成缩略图程序源代码
  14. leetcode 森林中的兔子
  15. 小程序登陆-微信小程序登录-支付宝小程序登录-头条小程序登录
  16. 用python输入三角形边长_python实现输入三角形边长自动作图求面积案例
  17. 阿里云轻量级应用服务器如何使用?
  18. 教程丨一文入门图像预训练模型
  19. Python Turtle 绘制蝴蝶曲线
  20. cgal配置以及一些资料

热门文章

  1. Vue 2.0 + Vue Router + Vuex 后台管理系统的骨架
  2. 蓝桥杯历届试题-六角填数(12)
  3. java分桃子_Java经典编程题分桃子
  4. redis数据类型 - Hash类型
  5. Python操作Redis:键(Key)
  6. mongodb修改最大连接数
  7. springMVC 拦截器简单配置
  8. 初级第四旬06— 回向与发愿试题
  9. 支持统一码 10 的花园明朝字库终于更新出来了
  10. VS2005的类设计器(Class Designer)中,如果显示让类继承接口,而不是实现接口?