目录

1.C++属性

2.静态断言(static_assert)

3.final、default、delete关键字的使用

4.成员变量初始化

5.类型别名

6.委托构造函数

7.const、volatile、mutable关键字

8.防止头文件重复引入

9.auto/decltype自动类型推导

10.智能指针

11.Lambda表达式


C++标准更新迭代非常快,我们熟悉的标准有C++98,C++11,C++14,其实最新的标准已经到C++20了但是支持该标准的IDE还很少。其实对于很多人来说,能掌握到C++14已经非常不错了。但是事实上是很多人对C++的掌握还停留在C++98上,连11的很多新特性都没有用到。C++新标准引入的新特性能提高编程的效率和代码的鲁棒性,学习一下对程序员的编程实战大有裨益,这里我结合一下自己的学习笔记和理解,总结了一下,希望对大家有所帮助。

这里提一句,之前在极客时间上学习了罗剑锋老师的C++实战笔记,感觉非常不错,收获也挺大的,建议感兴趣的可以去学习一下。

闲话少说,开始正文。

1.C++属性

C++的属性,主要用来控制程序的编译指令的, 针对C++属性标准并没有引入新的关键字,而是用两对中括号的形式来进行表示[[*****]],方括号中间可以添加对应的属性标签。

C++11中只定义了noreturn和carries_dependency两个属性标签,用处并不大。

C++14中定义了deprecated用来标记不推荐使用的函数或者类,使用该标签代表着这个函数或者类被废弃了。

使用方法如下:

[[deprecated("deadline:2021-10-16")]]
int test_fun();

如何在调用该函数的地方在编译的时候都会弹出下面的警告信息

warning: 'int test_fun' is deprecated: deadline:2021-10-16

在发布对外的库的时候,如果要提示用户接口或者类即将废弃,可以使用该属性标签,同时在我们编码的过程中如果要升级一个或者废弃一个接口也可以使用该属性标签。C++17和C++20又增加了五六个属性,比如fallthrough、likely等等。

现在的VS2015对C++14的支持还挺全面的,如果你的IDE是VS2015该特性可以放心使用

2.静态断言(static_assert)

静态断言和普通断言的区别就是,静态断言在编译的过程中生效,普通断言在运行过程中生效。静态断言可以用来在编译构造过程中进行断言检查。

//通过long类型的大小来判断是否运行在x64位系统上
//如果不满足条件,会提示对应的信息
static_assert(sizeof(long) >= 8,"must run on x64")//判断模板的实例化类型,假设T是个模板参数即template<typename T>
//搭配标准库里面的type_traits使用
//可以通过静态编译来限制模板实例化的类型
static_assert(is_integral<T>::value,"int");
static_assert(is_pointer<T>::value, "ptr");

3.final、default、delete关键字的使用

在继承关系中通过C++11的关键字final阻断继承关系,显式的禁用继承,防止其他人有意或者无意的产生派生类。

class ClassInterface
{...}class Implement final: public MyClassInterface
{...}

C++类里面,原先有四大函数,分别为:构造函数、析构函数、拷贝构造函数、拷贝赋值函数。C++11因为引入了右值和转移,又多出了两大函数:转移构造函数和转移赋值函数。

对于比较重要的构造函数和析构函数,如果不想自己写, 应该使用“=default”,明确指明,应该实现这个函数,但采用默认的形式。

class TestClass final
{public:TestClass() = default;  //采用默认构造~TestClass() = default;  //采用默认析构
}

C++11还引入了“=delete”的形式,明确指明禁用某个函数形式,不仅限于构造/析构,还可以用于任何函数(成员函数\自由函数)。

class TestClass final
{public:TestClass(const TestClass&) = delete;   //禁止拷贝构造TestClass& operator=(const TestClass&) = delete; //禁止拷贝赋值
}

4.成员变量初始化

在C++11中可以在成员变量声明的时候对其进行初始化。

class DemoTest final
{private:int x = 20;string m_test = "hello";public:DemoTest() = default;~DemoTest() = default;
}

5.类型别名

C++11扩展了关键字using的用法,增加了typedef的能力,可以定义类型的别名,它的格式与typedef正好相反,别名在左,原名称在右边。

using uint_t = unsigned int;  //using别名
typedef unsigned int uint_t;  //等价的typedef
class TestClass final
{public:using this_type = DemoClass;public:using string_type = std::string;using uint32_type = uint32_t;private:string_type  m_name = "tom";uint32_type  m_age = 32;
}

6.委托构造函数

在C++11中,可以使用委托构造函数新特性,一个构造函数直接调用另外一个构造函数。这样我们可以对构造函数进行封装,对外暴露出统一的构造函数。

class DemoClass final
{private:int a;public:DemoDelegating(int x): a(x){}DemoDelegating():DemoDelegating(0){}DemoDelegating(const string& s):DemoDelegating(stoi(s)){}
}

7.const、volatile、mutable关键字

1.const

const是一个类型修饰符,可以给任何对象附加上“只读”属性,保证安全。它可以用来修饰引用和指针,const& 可以引用任何类型,是函数入口参数的最佳类型。它还可以修饰成员函数,表示函数“只读”的,const 对象只能调用const成员函数

2.volatile

它表示变量可能被“不被察觉”的修改,禁止编译器优化,影响性能,应当少用

3.mutable

它用来修饰成员变量,允许const成员函数修改,mutable变量的变化不影响对象的常量性,但要小心不要误用损坏对象。

C++11里面mutable多了一种用法,可以修复师lambda表达式。

C++11引入了新关键字constexpr,能够表示真正的编译阶段常量,甚至能够编写在编译阶段运行的数值函数。

8.防止头文件重复引入

VS编译器支持指令#pragma once ,也可以实现“#Include Guard”,但它不是标准的,不能跨平台,不推荐使用。在引入头文件的时候,为了防止头文件重复引用,通过宏定义来实现。

#ifndef _XXX_H_HEADER_
#define _XXX_H_HEADER_
...
#endif

虽然这种手法比较原始,但目前来说是唯一有效的方法,而且向下兼容C语言,建议强制使用。

9.auto/decltype自动类型推导

auto避免了对类型的“硬编码”,也就是说类型不是写死的,而是自动推导出来的。但是auto有固定的使用场景要注意。

1.auto的自动推导能力,只能用于“初始化”的场合。包括赋值初始化和花括号初始化,变量右边必须有一个表达式。如果只是变量声明是无法使用auto的。在类成员变量初始化的时候,目前C++不支持推导类型。

2.auto总是推导出的“值类型”,绝对不是“引用类型”

3.auto可以附加上const、volatile、*、&这样的类型修饰符,得到新的类型。

auto   j  = 1000L;   //auto推导类型为long,j是long
auto&  j1 = j;       //auto是long j1是long&
auto*  j2 =&j;      //auto是long,j2是long*
const auto & j3 = j;//auto是long ,j3是const long&
auto j4 = &j3;      //auto的推导类型是const long* j4是const long*

auto自动类型推导,要求必须要从表达式推导。而decltype的形式很像函数,后面的圆括号里添加用于计算类型的表达式,其它的和auto一样,也能加上const、*、&等修饰符。因为decltype自带表达式可以直接用来进行变量声明。

int x = 0;
decltype(x)     x1;   //推导为int,x1是int
decltype(x)&    x2;   //推到为int,x2是int&
decltype(x)*    x3;   //推导为int,x3是int*
decltype(&x)    x4;   //推导为int*,x4是int*
decltype(&x)*   x5;   //推导为int*,x5是int**
decltype(x2)    x6 = x2;//推导为int&,x6是int&,引用必须赋值

auto和decltype的区别:decltype不仅能够推导出值类型,而且还能推导出引用类型,也就是表达式的原始类型。decltype可以直接从一个引用类型的变量推导出引用类型,而auto就会把引用去掉,推导出值类型。

可以把decltype看成是一个真正的类型名称,用在变量声明、函数返回值/参数、模板参数等任何类型出现的地方。

using int_ptr = decltype(&x);  //int*
using int_ptr = decltype(x)&;  //int&

虽然decltype类型推导更加精准,但是表达式要书写两次,左边类型推导,右边初始化。为了解决这个问题,C++14新增了一个decltype(auto)的形式,既可以精确推导出类型又能像auto一样,使用方便。

int x = 0;
decltype(auto)  x1 = (x); //推导为int& (expr)是引用类型
decltype(auto)  x2 = &x;  //推导为int*
//在变量声明的时候尽量多用auto,在容器遍历的时候也可以使用auto
vector<int>  input_vector = {1,2,3,4};
for(const auto& index : input_vector){cout << index << "," //常量访问
}

在C++14里面auto新增了一个使用场景,能够推导返回值的类型。这样在写复杂函数的时候会很省事。

auot get_result_vector{std::vector<int> result = {1,2,3};return result;
}

C++14新增了字面量后缀“s”,表示标准字符串,可以通过auto str = "xxx"s;直接推导出std::string的类型。

decltype是auto的高级形式,更侧重于编译阶段的类型推导,所以常用在泛型编程里面,获取各种类型,配合typedef 或者using 更加方便。

//UNIX信号原型
void (*signal(int signo, void (*func)(int)))(int)//使用decltyp声明类型
using sign_func_ptr_t = decltyp(&signal);

在定义类的时候由于auto被禁止使用,可以使用decltype。

class TestClass final
{public:using vector_type = std::vector<int>;private:vector_type  m_vecotr;//推导出迭代器的类型using iter_type = decltype(m_vector.begin());iter_type m_pos;
}

10.智能指针

由于auto_ptr在资源转移过程中调用流程容易引出错误,C++11使用unique_ptr代替了auto_ptr。常用的两种智能指针,分别是unique_ptr和shared_ptr。

unqiue_ptr名字虽然听起来像指针,但实际上并不是指针,而是一个对象。离开作用域的时候自动释放。另外也没有定义加减运算,不能随意移动指针定制,避免指针越界等操作。也不能不初始化,声明候直接使用。

unique_ptr<int> ptr1(new int(66));
assert(*ptr1 = 66);
assert(ptr1 != nullptr);ptr1++;      //导致编译错误
ptr2 += 2;  //导致编译错误unique_ptr<int> ptr3 ; //未初始化的智能指针
*ptr3 = 42 ;            //错误操作了空指针

使用工厂函数make_unique()强制创建的时候必须初始化。make_unqiue()要求C++14。

auto ptr3 = make_uique<int>(48);
assert(ptr3 && *ptr3 == 48);

unique_ptr表示的所有权是唯一的,不允许共享,unique_ptr应用了C++的转移语意,同时禁止拷贝赋值,在指向另外一个unique_ptr赋值的时候,必须用std::move()显示的转移所有权。转移之后原先的unique_ptr变成了空指针。

auto ptr1 = make_unique<int>(42);
assert(ptr1 && *ptr1 == 42);auto ptr2 = std::move(ptr1);
assert(!ptr1 && ptr2);

尽量不要对unique_ptr进行赋值操作,让其完全自动化管理指针。

shared_ptr和unique_ptr最大的不同点是:它的所有权可以被安全的共享,也就是说支持拷贝赋值。

shared_ptr<int> ptr1(new int(10));
auto ptr2 = make_shared<int>(42);
auto ptr3 = make_shared<string>("mystring");

shared_ptr通过使用“引用计数”,实现了安全共享。shared_ptr具有完整的“值语义”,所以它可以在任何场景替代原始指针,而不用再担心资源回收的问题,比如用于容器存储指针、用于函数安全返回动态创建的对象。

shared_ptr的引用计数的存储和管理都是有成本的,过度的使用shared_ptr会降低运行效率。

shared_ptr的引用计数销毁在运行阶段会变得很复杂,很难确定真正释放资源的时机。如果析构函数有非常复杂,严重阻塞的操作,一旦shared_ptr在某个不确定的时间点析构释放资源,就会阻塞整个进程或者线程。

11.Lambda表达式

lambda表达式就地定义函数,限制它的作用域和生命周期,实现函数的局部化。

lambda表达式用起来也就更灵活自由,能对它做各种运算,生成新的函数。这就像是数学里的复合函数那样,把多个简单功能的小lambda表达式组合,变成一个复杂的大lambda表达式。

lambda表达式除了可以像普通函数一样使用外,还可以捕获外部变量

nt n = 100;
auto func = [=](int x){cout << x + n << endl};//按值捕获
auto func = [&](int x){cout << x*n << endl};  //按引用捕获
auto func = [=,&n](int x){cout << x/n << endl};//n按引用传递,其它的按值传递//定义嵌套的lambda表达式
//C++里面每个lambda表达式都是特殊类型只有编译器知道,所以用auto来声明
auto outerlambda = []()
{auto innerlambda = [](int x){return x*x;}
}

因为lambda表达式不是普通的变量,C++也鼓励程序员尽量匿名使用lambda表达式。也就是不必显示的命名,直接就地使用。我们可以使用STL+lambda来替代for循环。

vector<int> input = {1,2,3,4,5};
find_if(std::begin(input),std::end(input),[](int x){return x>=5});

建议你在使用捕获功能的时候要小心,对于“就地”使用的小lambda表达式,可以用“[&]”来减少代码量,保持整洁;而对于非本地调用、生命周期较长的lambda表达式应慎用“[&]”捕获引用,而且,最好是在“[]”里显式写出变量列表,避免捕获不必要的变量。

虽然目前在C++里,纯函数式编程还比较少见,但“轻度”使用lambda表达式也能够改善代码,比如用“map+lambda”的方式来替换难以维护的if/else/switch,可读性要比大量的分支语句好得多。

map<int, function<void()>> funcs;
funs[1] =[](){...};
funs[4] =[](){...};
funs[6] =[](){...};
return funcs[x]();
这样就把switch/case 转换成了function+lambda

lambda表达式的返回值类型可以自动推导(相当于用了auto),但有的时候必须明确指定返回值类型,在入口参数的圆括号后用“->type”的形式。

在按值捕获外部变量的时候,可以给lambda表达式加上mutable修饰,允许修改变量。注意,这与按引用捕获不同,修改的只是变量的拷贝,不影响外部变量的原值。

因为每个Iambda表达式的类型都是唯一的,所以即使函数签名相同,lambda变量也不能互相赋值。解决办法是使用标准库里的stdl:function类,它是“函数的容器”“智能函数指针”,可以存储任意符合签名的"可调用物"(callableobject)搭配使用能够让lambda表达式用起来更灵活。

呕心沥血梳理C++新标准超好用的新特性(实战必备)相关推荐

  1. TB/T3139-2021机车车辆有害物质限量新标准解读

    TB/T 3139标准为铁路机车材料环保标准,是测量机车车辆内装材料有害物质限量的标准. 国家铁路局于2021年3月5日批准发布TB/T 3139-2021<机车车辆非金属材料及室内空气有害物质 ...

  2. 21世纪的健康新标准

    著名的健康教育专家洪昭光教授再推健康新观念,主要观点有:     21世纪的健康新标准        21世纪的健康新标准应该是什么样的?洪昭光总结了几句话:"健康快乐100岁,天天都有好心 ...

  3. 5G新标准将延迟3个月发布,但5G“新战场”已经明确

    来源:雷锋网 2019年,5G开启商用元年.2020年开年,5G智能手机的发布就迎来了一个发布高峰,2月份至今,国内就有10多款5G手机发布.5G手机的数量和销量也迅速增长,根据工信部副部长辛国斌给出 ...

  4. 字节腾讯阿里罕见联手:发布直播技术新标准,要让手机直播像电视一样丝滑...

    明敏 发自 凹非寺 量子位 | 公众号 QbitAI 字节.阿里.腾讯3家大厂联手搞了件大事: 把传统直播3-6秒的延迟,直接拉低到1秒内大关,最低可到500毫秒的那种. 就在最近,火山引擎与阿里云. ...

  5. 阿里云加入开放媒体联盟AOM 科技巨头联合推广高清视频新标准

    谷歌.亚马逊.阿里巴巴.苹果等科技巨头正在推动一项高清视频媒体的新标准. 日前,阿里云宣布正式加入全球顶级视频标准组织--开放媒体联盟(Alliance for Open Media ,简称AOM), ...

  6. 创业新标准:客户发展方法+商业模式画布

    本文译自< 四步创业法 >作者 Steve Blank 的博客( 原文链接 ). 翻译:李丹立   审校:张彦 徐定翔 过去的50多年,计算机的制造工艺从独立的晶体管发展到封装的逻辑门,后 ...

  7. 5G未来如何发展?新标准透露的信息量太大

    "5G的商用速度比4G快很多.全球已有超过45家OEM厂商推出或宣布推出5G终端,超过50家运营商部署5G商用网络,超过345家运营商正在投资5G.从终端角度看,2022年5G手机出货量预计 ...

  8. 药店行政处罚新标准来了!15大行为千万别碰!

    在最严<药品管理法>下,药店行政处罚裁量标准变了. 01 药店行政处罚,新标准来了 近日,广东省药监局发布了<关于对广东省药品监督管理局规范行政处罚自由裁量权相关制度征求意见的公告& ...

  9. 安徽大学计算机系课程表,超智能! 安徽大学新学期 全面启用电子课表

    原标题:超智能! 安徽大学新学期 全面启用电子课表 9月3日,开学首日上午,安徽大学的学生们一来到教室门口,就看到一个"新设备",别小看这一块小小的显示屏,以后同学们查看每天的课表 ...

最新文章

  1. 刻意练习:Python基础 -- Task12. 模块
  2. MySQL基于ROW格式的数据恢复
  3. nyoj42一笔画问题
  4. idea中如何创建servlet文件
  5. OpenG 轮廓检测
  6. 新建Eclipse的web工程目录结构和MyEclipse相似的设置
  7. cocos2d-x游戏开发(八)各类构造器
  8. BX、DI、SI、BP总结
  9. 摄像头安装说明_老司机告诉你马路上不同摄像头有不同作用,注意区分小心扣分...
  10. if/else双分支(JS)
  11. flutter 弹幕插件_Flutter 实现虎牙/斗鱼 弹幕效果
  12. FI-MM-CO T-CODE (中英文)
  13. 如何高效完成英文文献翻译
  14. 关于bootbox.js自定义弹出框样式,如修改宽度等
  15. 什么是html文件?html格式如何打开?(图)
  16. python变成灰色_Python怎么把彩色图像转换成灰色图像?
  17. SPSS中的数据分析—信度效度检验【2】
  18. android手机传感器,安卓手机传感器
  19. 构建CA证书详解过程步骤
  20. element表格 频繁切换维度,导致表头渲染有误

热门文章

  1. 【深度分解】听趣拍云产品经理剖析视频基础知识(2)
  2. 转载国内私募界知名的操盘手刘文文的访问,收益匪浅
  3. 学习笔记1—元胞自动机(CA)模型①
  4. 自然语言处理(NLP)-NLTK入门学习(二)
  5. 白门柳-刘斯奋有声小说
  6. 学习记录之OLED显示屏(IIC)1
  7. 【前端】particle.js页面粒子效果
  8. VoLTE技术(含IMS注册/去注册流程、IMS呼叫流程、呼叫保持流程、二次协商过程)
  9. 从Internet时间服务器获取标准时间
  10. 解决谷歌浏览器不显示翻译此页按钮(网页自动翻译)