C++ Primer Plus第十八章笔记

2024-03-21 19:28

本文主要是介绍C++ Primer Plus第十八章笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1. 复习C++11功能

1.1 新类型

1.2 统一的初始化

1.2.1 缩窄

1.2.2 std::initializer_list

1.3 声明

1.3.1 auto

1.3.2 decltype

1.3.3 返回类型后置

1.3.4 模板别名:using

1.3.5 nullptr

1.4 智能指针

1.5 异常规范的修改

1.6 作用域内枚举

1.7 对类的修改

1.8 模板和STL方面的修改

1.9 右值引用

2. 移动语义和右值引用

2.1 需要移动语义的原因

2.2 移动构造函数

2.3 赋值

3. 新的类功能

3.1 特殊的成员函数

3.2 默认的方法和禁用的方法

3.3 委托构造函数

3.4 继承构造函数

3.5 管理虚方法:override和 final

4. Lambda函数

4.1 比较函数指针、函数符和Lambda函数

4.2 使用Lambda原因

5. 包装器

5.1 包装器function及模板的低效性

6. 可变参数模板

6.1 模板和函数参数包

6.2 展开参数包中使用递归

7. C++11新增的功能

7.1 并行编程

7.2 新增的库

7.3 低级编程


1. 复习C++11功能

1.1 新类型

C++11新增类型:

  • 整型
    • long long
    • unsigned long long
  • 字符表示
    • char16_t
    • char32_t

1.2 统一的初始化

C++11 扩大了用大括号起的列表(初始化列表)的适用范围。使其可用于所有内置类型用户定义类型(即类对象)。列表初始化的三种方式:

使用初始化列表时,可添加等号(=),也可不添加。
int x = {5};
short quar[5] {4,5,6,2,1};
可以用于new表达式中
int *ar = new int [4] {2,4,6,7}; C++11
创建对象时,可使用大括号(而不是圆括号)括起来的列表来调用构造函数。
class Stump
{private:int roots;double weight;public:Stump(int r,rouble w) : roots(r), weight(w) {}
};
Stump s1(3,15.6); // old style
Stump s2{5,43.4}; // C++11
Stump s3{4,32.1}; // C++11
1.2.1 缩窄
  • 初始化列表语法可防止缩窄,即禁止将数值赋给无法存储它的数值变量,即将值存储到比它“窄”的变量中。

  • 编译器会禁止变窄类型的转换,但允许在范围内变宽的转换。

1.2.2 std::initializer_list
  • C++11中提供 initializer_list模板类,可用作构造函数的参数。

  • 如果类有接受 initializer_list 作为参数的构造函数,则初始化列表语法就只能用于该构造函数。

  • 列表中的元素必须是同一种类型或者可转换为同一种类型

1.3 声明

1.3.1 auto
  • C++11使用auto关键字实现自动类型推断

  • 要求进行显式初始化,让编译器能够将变量的类型设置为初始值的类型。

  • auto关键字也可简化模板声明

1.3.2 decltype
  • decltype关键字:将变量的类型声明为表达式指定的类型。

    template <typename T, typename U>
    void ef(T t, U u)
    {decltype(T*U) tu;...
    }

1.3.3 返回类型后置
  • C++11新增函数声明语法:在函数名和参数列表后面指定返回类型。

    double f1(double,int); // 传统方式
    auto f2(double,int)->double; // C++11中的新语法
  • 使用 decltype来指定模板函数的返回类型:

    template<typename T, typename U>
    auto eff(T t, U u) -> decltype(T*U)
    {// 当编译器遇到 ef的参数列表时,T和 U不再作用域内,因此必须在参数列表后使用decltype。....
    }
1.3.4 模板别名:using

解决标识符冗长或复杂的问题。

  • 早期使用 typedef
    • 不能用于模板部分具体化
    typedef std::vector<std::string>::iterator itType;
  • C++11提供 using=
    • 可用于模板部分具体化
    template <typename T>
    using arr = std::array<T,int>; // 模板部分具体化
1.3.5 nullptr

C++11 新增关键字 nullptr来表示空指针。它是指针类型,不能转换为整型类型。

为向后兼容,C++11仍允许使用 0 来表示空指针,因此表达式 nullptr==0 为 true

1.4 智能指针

因为在程序中使用 new 分配内存,未将其及时 delete释放。引入智能指针auto_ptr

C++11抛弃auto_ptr,并新增了三种智能指针:unique_ptrshared_ptr 和 weak_ptr

1.5 异常规范的修改

指出函数不会引发异常有一定的价值,所以C++11添加了关键字noexpect

void f875(short, short) noexpect; // 不会抛出异常

1.6 作用域内枚举

在C++11中新增一种枚举。使用 class 或者 struc t来定义。

enum old1 {yes,no,maybe}; // 传统方式
enum class New1 {never,sometimes,often,always}; // 新方式
enum struct New2 {never,lever,sever}; // 新方式

新枚举要求进行显式限定,以避免名称冲突。所以在引用枚举时,则使用

New1::never;
New2::never;

1.7 对类的修改

  • 显式转换运算符

    • 早期的自动类型转换会导致意外问题,所以在C++11中引入关键字 explicit,以禁止单参数构造函数导致的自动转换
  • 类内成员初始化

    • 可使用等号或者大括号版本的初始化,但不能使用圆括号版本的初始化。
    • 类内成员初始化,可避免在构造函数中编写重复的代码。

1.8 模板和STL方面的修改

  • 基于范围的for循环

    double price[5] = {4.99,10.99,6.87,7.99,8.49};
    for (auto x : price)std::out << x << std::endl;
    • 如果要在循环中修改数组或容器中的每个元素,可使用引用类型。
  • 新的STL容器

    • C++11新增STL容器:forward_listunordered_mapunordered_multimapunordered_setunordered_multiset
    • C++11新增模板array,实例化时,可指定元素类型和固定的元素数。
  • 新的STL方法

    • C++11新增STL方法
      • cbegin()
      • cend()
      • crbegin()
      • crend()
    • 其中 crbegin()crend() 是 rbegin()rend() 的const版本。
    • 除传统的复制构造函数常规赋值运算符外,STL容器还有移动构造函数移动赋值运算符
  • valarray升级

    • C++11中添加了两个函数 begin() 和 end()。都接受 valarray 作为参数,并返回迭代器。
  • 抛弃export

    • C++98新增
    • C++终止用法,但为了兼容还保留关键字 export。
  • 尖括号

    • C++在声明嵌套模板时不再需要使用空格将尖括号分开。

1.9 右值引用

  • 左值引用

    • 左值:一个表示数据的表达式,程序可获取其地址。
    • 左值出现在赋值语句的左边,但修饰符的出现const使得声明的标识符,即不能给它赋值,但可获取其地址。
    int n;
    int * pt = new int;
    const int b = 101; // 不能赋值,
    int & rn = n;
    int & rt = *pt;
    const int &rb = b; // b标识符const引用地址

  • 右值引用

    • C++11新增右值引用,使用 && 表示。右值引用可以关联到右值,即可出现在赋值表达式右边,但不能对其应用地址运算符的值
    • 右值包括:字面常量表达式返回值的函数(函数返回的不能是引用)。
    • 引入右值引用的主要目的之一:实现移动语义
    int x = 10;
    int y = 23;
    int && r1 = 13; // 字面常量
    int && r2 = x + y;  // 表达式
    double && r3 = std::sqrt(2.0); // 函数返回值

2. 移动语义和右值引用

2.1 需要移动语义的原因

  • 常规复制构造函数

    • 使用 const左值引用作为参数,使得引用关联到左值实参
    • 可执行深复制
  • 移动构造函数

    • 使用右值引用作为参数,将引用关联到右值实参
    • 只调整记录
    • 在将所有权转移给新对象的过程中,移动构造函数可能修改其实参,意味着右值引用参数不应是const

2.2 移动构造函数

代码示例

2.3 赋值

  • 适用于构造函数的移动语义考虑也适用于赋值运算符。

3. 新的类功能

3.1 特殊的成员函数

  • 原有的4个特殊成员函数
    • 默认构造函数
    • 复制构造函数
    • 复制赋值运算符
    • 析构函数
  • C++新增的2个
    • 移动构造函数
    • 移动赋值运算符

这些成员函数是编译器在各种情况下自动提供的。

  • 如果提供了析构函数、复制构造函数或者复制赋值运算符,编译器将不会自动提供移动构造函数移动赋值运算符
  • 如果提供了移动构造函数移动赋值运算符,编译器将不会自动提供复制构造函数复制赋值运算符

3.2 默认的方法和禁用的方法

  • C++11中如果提供了移动构造函数,所以编译器不会自动创建默认的构造函数、复制构造函数和复制赋值构造函数。可使用关键字 default 显式声明方法的默认版本。

    class Someclass
    {public:Someclass(Someclass &&);Someclass() = default;Someclass(const Someclass &) = default;Someclass & operator=(const Someclass &) = default;...
    };
  • 关键字 delete 可用于禁止编译器使用特定方法。

    • 也可禁止特定的转换
  • 关键字 default只能用于6个特殊成员函数,但delete可用于任何成员函数

3.3 委托构造函数

  • C++11 允许在一个构造函数的定义中使用另一个构造函数,这种方式称为 委托
Notes::Notes(int kk,double xx) : Notes(kk,xx,"Uh") {/**/}

3.4 继承构造函数

  • C++98 使用名称空间中函数可用的方式。

  • C++11 中使用派生类继承基类的所有构造函数(默认构造函数、复制构造函数和移动构造函数除外),但不会使用与派生类构造函数的特征标匹配的构造函数

3.5 管理虚方法:override和 final

  • 在C++11中,可使用虚说明符override指出要覆盖一个函数,将其放在参数列表后面。如果声明与基类方法不匹配,编译器将视为错误。

  • final说明符禁止派生类覆盖特定的虚方法,所以在参数列表后面加上final

  • overridefinal非关键字,而是具有特殊含义的标识符

4. Lambda函数

Lambda 函数,也叫做Lambda表达式。

匿名函数无需给出函数命名。

4.1 比较函数指针、函数符和Lambda函数

在C++11中,对于接受函数指针或者函数符的函数,可使用匿名函数定义作为其参数。

匿名函数与函数的区别:

  • 使用 [] 替代 函数名
  • 没有声明返回类型(返回类型相当于使用decltype根据返回值推断得到)
  • 如果lambda不包含返回语句,推断出的返回类型将为void
[] (int x) {return x % 3 == 0;}

当且仅当, lambda表达式完全由一条返回语句组成时,自动类型推断才管用。否则,需要使用新增的返回类型后置语法:

[] (double x)-> double{int y = x; return x - y;} // 返回类型为double

匿名函数代码示例

4.2 使用Lambda原因

四个角度来分析

  • 距离
    • 函数定义离使用地点近。
  • 简洁
    • 函数符代码比函数和lambda代码更繁琐。
  • 效率
    • 三种方式的相对效率取决于编译器内联。
  • 功能
    • lambda可访问作用域内任何动态变量
    • 要捕获使用的变量,可将其名称放在中括号内。
      • 如果只指定变量名,如[z],则将值访问变量
      • 如果在名称前加上 &,如[&count],则按引用访问变量
    • [&] 按引用访问所有动态变量
    • [=] 按值访问所有动态变量。

函数指针方法阻止内联,因为编译器传统上不会内联其他地址被获取的函数,因为函数地址的概念意味着非内联函数。而函数符lambda通常不会阻止内联

可以给lambda指定一个名称,然后使用名称来替代。

auto mod3 = [] (int x) {return x % 3 == 0;} // mod3 a name for the lambdacount1 = std::count_if(n1.begin(),n1,end(),mod3);
count2 = std::count_if(n2.begin(),n2.end(),mod3);

C++中引入lambda的主要目的:能将类似于函数的表达式用做接受函数指针或函数符的函数的参数。

5. 包装器

C++提供多个包装器wrapper,也叫做适配器(adapter))。

C++11中提供了其他的包装器:

  • bind
    • 可替代 bind1st 和 bind2nd
  • mem_fn
    • 可将成员函数作为常规函数进行传递
  • reference_wrapper
    • 能创建行为像引用但可被复制的对象
  • function
    • 以统一的方式处理多种类似于函数的形式

5.1 包装器function及模板的低效性

模板function 是在头文件functional 中声明,从调用特征标的角度定义了一个对象,可用于包装调用特征相同的函数指针、函数对象或者lambda表达式。

// 接受一个char参数和一个int参数,并返回一个double值的任何函数指针、函数对象或者lambda表达式赋值给它
std::function<double>(char, int) > fdci;

6. 可变参数模板

要创建可变参数模板,需要理解以下要点:

  • 模板参数包(parameter pack)
  • 函数参数包
  • 展开参数包
  • 递归

6.1 模板和函数参数包

C++11中提供省略号表示的元运算符(meta-operator)。

  • 模板参数包:可以声明表示模板参数包的标识符,模板参数包是一个类型列表
  • 函数参数包:可以声明表示函数参数包的标识符,函数参数包是一个值列表
// Args可以与任意数量的类型匹配
template <typename... Args> // Args 是模板参数包
void show_list(Args...args) // args 是函数参数包
{...
}

6.2 展开参数包中使用递归

将函数参数包展开,对列表中的第一项进行处理,再将余下的内容传递给递归调用,以此类推,直到列表为空。

template <typename T ,typename...Args>
void show_list(T value, Args..args) 
{show_list(args...);
}// 对于按值传递来说,效率低,所以可更改为;
void show_list1(const T& value, const Args&... args)
{show_list1(args...);
}

7. C++11新增的功能

7.1 并行编程

为解决并行性的问题,C++定义了一个支持线程化执行的内存模型,添加了关键字 thread_local ,提供了相关库支持。

关键字 thread_local 将变量声明为静态存储,其持续性和特定线程相关,即定义变量的线程过期时,变量也过期

库支持由原子操作(automic、operation)库线程支持库组成。原子操作库提供的头文件:

  • thread
  • mutex
  • condition
  • variable
  • future

7.2 新增的库

在C++11中新增专用的头文件库

  • random:随机数扩展工具
  • chrono:处理时间间隔的途径
  • tuple:支持模板tuple。
  • ratio:编译阶段的有理数算术库
  • regex:正则表达式库。用于指定与文本字符串的内容匹配。

7.3 低级编程

低级编程中的“低级”指的是抽象程度,而不是编程质量。

C++11给低级编程人员提供的两个便利:

  • 放松了POD(Plain Old Data)的要求。
  • 允许共用体的成员构造函数析构函数

这篇关于C++ Primer Plus第十八章笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/833672

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现