| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> 现代C++教程笔记(上) -> 正文阅读 |
|
[C++知识库]现代C++教程笔记(上) |
文章目录前言链接: 第 1 章 迈向现代 C++C++ 不是 C 的一个超集: C++特性在GCC/Clang等编译器中的支持情况: 第 2 章 语言可用性的强化constexpr:
C++11 提供了 constexpr 让用户显式的声明函数或对象构造函数在编译期会成为常量表达式。 这个关键字明确的告诉编译器应该去验证 len_foo 在编译期就应该是一个常量表达式。此外,constexpr 修饰的函数可以使用递归,且从 C++14 开始,constexpr 函数可以在内部使用局部变量、循环和分支等简单语句。 if/switch 变量声明强化在传统 C++ 中,终没有办法在 if 和 switch 语句中声明一个临时的变量。C++17 消除了这一限制,使得我们可以在 if(或 switch)中完成这一操作。 比如如下代码:
报错: VS2019中在这改: 初始化列表见我的笔记第五点——initializer_list: 结构化绑定C++11 新增了 std::tuple 容器用于构造一个元组。我们可以使用 std::tie 对元组进行拆包,但我们依然必须非常清楚这个元组包含多少个对象,各个对象是什么类型,非常麻烦。 C++17 完善了这一设定,给出了 结构化绑定。 测试如下:
可以看到,我们可以用get访问,或是tie拆包,但是用结构化绑定的方法,直接 auto [x, y, z] = my_tuple; 实在是方便。上述代码打印出来是3个 hbh 关于tie: 类型推导auto不用多说,decltype可见我的笔记: std::is_same<T, U> 用于判断 T 和 U 这两个类型是否相等。 注意:typename 和 class 在模板参数列表中没有区别,在 typename 这个关键字出现之前,都是使用 class 来定义模板参数的。但在模板中定义有嵌套依赖类型的变量时,需要用 typename 消除歧义 尾返回类型(trailing return type):
同时 C++14 还开始提供 decltype(auto) 。decltype(auto) 主要用于对转发函数或封装的返回类型进行推导,它使我们无需显式的指定 decltype 的参数表达式。 if constexprC++17 将 constexpr 这个关键字引入到 if 语句中,允许在代码中声明常量表达式的判断条件。 本质上是通过 C++11 引入的 constexpr 关键字,它将表达式或函数编译为常量结果。把这一特性引入到条件判断中去,让代码在编译时就完成分支判断,从而让程序效率更高。 面向对象委托构造和继承构造
上述代码的结果为:Subclass 通过继承构造调用了 Base(int value),使得 value2 为 3,而 注意(源于https://www.runoob.com/w3cnote/cpp11-inheritance-constructor.html): 1.对于继承构造函数来说,參数的默认值是不会被继承的,并且,默认值会 导致基类产生多个构造函数版本号(即參数从后一直往前面减。直到包括无參构造函数,当然假设是默认复制构造函数也包括在内),这些函数版本号都会被派生类继承。 2.继承构造函数中的冲突处理:当派生类拥有多个基类时,多个基类中的部分构造函数可能导致派生类中的继承构造函数的函数名。 3.假设基类的构造函数被声明为私有构造函数或者派生类是从基类虚继承的,那么就不能在派生类中声明继承构造函数。 4.假设一旦使用了继承构造函数,编译器就不会为派生类生成默认构造函数。这样,我们得注意继承构造函数无參版本号是不是有须要。(比如这里在 Subclass 中新增成员 int b,结果仍然不会变,编译器没有为派生类生成默认构造函数) 显式虚函数重载C++11 引入了 override 和 final 这两个关键字,前者将显式的告知编译器进行重载,编译器将检查基函数是否存在这样的虚函数,否则将无法通过编译;后者则是为了防止类被继续继承以及终止虚函数继续重载引入的。 于我的笔记第11点: 同时下一节显示禁用默认函数也可见我的笔记,不再记录。 强类型枚举C++11 引入了枚举类(enumeration class),并使用 enum class 的语法进行声明:
再比如示例代码:
上述代码可以正常打印出值1,但是要是改写成:enum a 和 enum b,即不用枚举类,则会报错: 错误 C2365 “hbh1”: 重定义;以前的定义是“枚举数” 可见:在传统 C++中,枚举类型并非类型安全,枚举类型会被视作整数,则会让两种完全不同的枚举类型可以进行直接的比较(虽然编译器给出了检查,但并非所有),甚至同一个命名空间中的不同枚举类型的枚举值名字不能相同,这通常不是我们希望看到的结果。 第 3 章 语言运行期的强化Lambda于我的笔记第13点: std::functionC++11 std::function 是一种通用、多态的函数封装, 它的实例可以对任何可以调用的目标实体进行存储、复制和调用操作, 它也是对 C++ 中现有的可调用实体的一种类型安全的包裹(相对来说,函数指针的调用不是类型安全的), 换句话说,就是函数的容器。当我们有了函数的容器之后便能够更加方便的将函数、函数指针作为对象进行处理。 原书的两个示例代码写的很好了,建议看原书。 std::bind 和 std::placeholderstd::bind 是用来绑定函数调用的参数的,std::placeholder 是作为占位符,这在侯捷老师的 STL 源码剖析 中有详细分析。 右值引用见我的笔记: 补充: C++11 中为了引入强大的右值引用,将右值的概念进行了进一步的划分,分为:纯右值、将亡值。 纯右值(prvalue, pure rvalue),纯粹的右值,要么是纯粹的字面量,例如 10, true; 要么是求值结果相当于字面量或匿名临时对象,例如 1+2。非引用返回的临时变量、运算表达式产生的临时变量、 原始字面量、Lambda 表达式都属于纯右值。 (需要注意的是,字符串字面量只有在类中才是右值,当其位于普通函数中是左值。) 将亡值(xvalue, expiring value),是 C++11 为了引入右值引用而提出的概念(因此在传统 C++ 中, 纯右值和右值是同一个概念),也就是即将被销毁、却能够被移动的值。 引用坍缩(折叠)规则:
第 4 章 容器这一章讲了std::array、std::forward_list、无序容器、tuple。 由于我看过 STL源码剖析,大部分都学过,这一章只做关于tuple的一些补充。 补充: 关于元组的使用有三个核心的函数:
tuple运行期索引——通过std::variant<>std::get<> 依赖一个编译期的常量,所以下面的方式是不合法的:
解决方法是使用 C++ 17 引入的 std::variant<> ,提供给 variant<> 的类型模板参数 可以让一个 variant<> 从而容纳提供的几种类型的变量(在其他语言,例如 Python/JavaScript 等,表现为动态类型) tuple合并与遍历合并两个元组,这可以通过 std::tuple_cat 来实现:
而通过for循环遍历一个元组,首先需要知道它的长度,之后就可以通过之前讲的运行期索引取遍历了。 那么长度我们可以用两种方法:
一种是写了一个函数模板tuple_len,另一种干脆直接using TupleType = tuple<int, double>; 不过明显第一种更具通用性。 tuple小结std::tuple 虽然有效,但是标准库提供的功能有限,没办法满足运行期索引和迭代的需求,好在我们还有其他的方法可以自行实现。 第 5 章 智能指针与内存管理以下摘抄书原文: 通常的做法是对于一个对象而言,我们在构造函数的时候申请空间,而在析构函数(在离开作用域时调用)的时候释放空间, 也就是我们常说的 RAII 资源获取即初始化技术。 但是对于需要将对象在自由存储上分配的需求,在传统 C++ 里我们只好使用 new 和 delete 去 『记得』对资源进行释放。而 C++11 引入了智能指针的概念,使用了引用计数的想法,让程序员不再需要关心手动释放内存。 这些智能指针就包括 std::shared_ptr/std::unique_ptr/std::weak_ptr,使用它们需要包含头文件 <memory> 。 注意:引用计数不是垃圾回收,引用计数能够尽快收回不再被使用的对象,同时在回收的过程中也不会造成长时间的等待, 更能够清晰明确的表明资源的生命周期。 这一章节同样在我的笔记: std::shared_ptrstd::make_shared 能够用来消除显式的使用 new,所以std::make_shared 会分配创建传入参数中的对象, 并返回这个对象类型的std::shared_ptr指针。 std::shared_ptr 可以通过 get() 方法来获取原始指针,通过 reset() 来减少一个引用计数, 并通过use_count()来查看一个对象的引用计数。
std::unique_ptr书上说 C++11 没有提供 std::make_unique,但是各家编译器似乎自己实现了。 我们自行实现一个 make_unique 可如下:
最近在看D3D12龙书,里面的示例代码就经常会用到make_unique,我在VS2019下查看源码如下(头文件memory中): std::weak_ptr引出弱指针主要是为了解决 std::shared_ptr 循环包含问题(水平有限,不知道还有别的用途没有): std::weak_ptr是一种弱引用(相比较而言 std::shared_ptr 就是一种强引用)。弱引用不会引起引用计数增加。 std::weak_ptr 没有 * 运算符和 -> 运算符,所以不能够对资源进行操作,它的唯一作用就是用于检查 std::shared_ptr 是否存在,其 expired() 方法能在资源未被释放时,会返回 false,否则返回 true。 总结智能指针这种技术并不新奇,在很多语言中都是一种常见的技术,现代 C++ 将这项技术引进,在一定程度上消除了 new/delete 的滥用,是一种更加成熟的编程范式。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/29 3:54:15- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |