Skip to content

Latest commit

 

History

History
200 lines (157 loc) · 17.1 KB

17.md

File metadata and controls

200 lines (157 loc) · 17.1 KB

十七、答案

第一章

  1. 从源代码生成可执行文件的过程称为编译。编译 C++ 程序是导致机器代码生成的一系列复杂任务。通常,C++ 编译器解析和分析源代码,生成中间代码,优化它,最后在一个名为目标文件的文件中生成机器代码。另一方面,解释器不产生机器代码。相反,它逐行执行源代码中的指令。
  2. 首先是预处理,然后编译器通过解析代码、执行语法和语义分析来编译代码,之后生成中间代码。优化生成的中间代码后,编译器生成最终目标文件(包含机器代码),然后可以将其与其他目标文件链接。
  3. 预处理器旨在处理源文件,使它们为编译做好准备。预处理器使用预处理器指令,如#define#include。指令不代表程序语句,但它们是给预处理程序的命令,告诉它如何处理源文件的文本。编译器无法识别这些指令,因此每当您在代码中使用预处理器指令时,预处理器都会在代码的实际编译开始之前相应地解析它们。
  4. 编译器为每个编译单元输出一个目标文件。链接器的任务是将这些目标文件组合成一个目标文件。
  5. 库可以作为静态或动态库与可执行文件链接。当您将它们链接为静态库时,它们会成为最终可执行文件的一部分。操作系统还应该将动态链接库加载到内存中,以便为程序提供调用其函数的能力。

第二章

  1. 通常,main()函数有两个参数,argcargv,其中argc是程序的输入参数数量,argv构成这些输入参数。非常偶然的情况下,你可以看到一个被广泛支持但不规范的第三个论点,最常见的名字是envpenvp的类型是一个字符指针数组,它保存系统的环境变量。
  2. constexpr说明符声明可以在编译时计算该函数的值。同样的定义也适用于变量。名称由const和表达式组成。
  3. 递归导致为函数调用分配额外的空间。与迭代解决方案相比,为函数和调用分配空间是昂贵的。
  4. 堆栈保存具有自动存储持续时间的对象;也就是说,程序员不关心内存中那些对象的构造和销毁。通常,堆栈用于函数参数和局部变量。另一方面,堆允许在程序执行期间分配新的内存。然而,正确地释放内存空间现在是程序员的责任。
  5. 指针的大小不取决于指针的类型,因为指针是一个代表内存中地址的值。地址的大小取决于系统。通常,它不是 32 位就是 64 位。因此,我们说指针的大小是 4 或 8 字节。
  6. 就项目位置而言,数组具有独特的结构。它们被连续地放置在内存中;第二项放在第一项之后,第三项放在第二项之后,依此类推。考虑到这个特性,以及数组由相同类型的元素组成这一事实,在任何位置访问一个项目都需要恒定的时间。
  7. 如果我们忘记了case语句中的break关键字,执行将传递到下一个case语句,而不检查其条件。
  8. 例如operations['+'] = [](int a, int b) { return a + b; }

第三章

  1. 身份、状态和行为。
  2. 当移动对象而不是复制时,我们省略了临时变量的创建。
  3. 在 C++ 中,除了默认的访问修饰符之外,结构和类没有任何区别。这对于结构是公共的,对于类是私有的。
  4. 在聚合的情况下,包含其他类的一个或多个实例的类可以在没有聚合的情况下被实例化。另一方面,这篇作文表达了强烈的包容。
  5. 私有继承从派生类的客户端代码中隐藏继承的成员。受保护的继承也是如此,但允许链中的派生类访问这些成员。
  6. 通常,虚函数的引入导致用指向虚函数表的附加数据成员来扩充类。通常,这将为类对象增加 4 或 8 字节的空间(基于指针的大小)。
  7. Singleton 设计模式允许构造类的单个实例。这在很多项目中很有帮助,在这些项目中,我们需要确保类的实例数量被限制在一个。例如,数据库连接类如果实现为 Singleton,效果最好。

第四章

  1. 如果使用得当,宏是强大的工具。但是,以下方面限制了宏的使用。(1)不能调试宏;(2)宏观扩张会导致奇怪的副作用;(3)宏没有命名空间,所以如果您有一个宏与其他地方使用的名称冲突,您会在不想要的地方获得宏替换,这通常会导致奇怪的错误消息;(4)宏可能会影响你不知道的事情。详情请前往https://stackoverflow.com/questions/14041453

  2. 类/函数模板是指一种用于生成模板类/函数的模板。它只是一个模板,而不是一个类/函数,因此编译器不会为它生成任何目标代码。模板类/函数是类/函数模板的一个实例。由于它是一个类/函数,相应的目标代码由编译器生成。

  3. 我们定义类/函数模板时,template关键字后有一个<>符号,其中必须给出一个或多个类型参数。< >中的类型参数称为模板参数表。当我们实例化一个类/函数模板时,所有的模板参数都必须用它们对应的模板参数来替换,这就是所谓的模板参数列表。

隐式实例化按需发生。但是,当提供库文件(.lib)时,您不知道用户将来将使用什么类型的参数列表,因此,您需要显式实例化所有潜在的类型。

  1. 多态性是指某物以不同的形式存在。具体来说,在编程语言中,多态性意味着一些函数、操作或对象在不同的上下文中有几种不同的行为。在 C++ 中,多态有两种:动态多态和静态多态。动态多态性允许用户在运行时确定要执行的实际函数方法,而静态多态性意味着要调用的实际函数(或者一般来说,要运行的实际代码)在编译时是已知的。

函数重载意味着用相同的名称定义函数,但是使用不同的参数集(不同的签名)。

函数重写是子类重写父类中定义的虚拟方法的能力。

  1. 类型特征是一种用于收集类型信息的技术。在它的帮助下,我们可以做出更智能的决策来 在泛型编程中开发高质量的优化算法。类型特征可以通过部分或全部模板专门化来实现。
  2. 我们可以在g()中写一个错误语句,并构建代码。如果一个未使用的函数被实例化,编译器将报告错误,否则它将被成功构建。您可以在以下文件中找到示例代码:ch4_5_class_template_implicit_inst_v2.hch4_5_class_template_implicit_inst_B_v2.cpp,网址为。/树/主/第 4 章。
  3. 参见中的ch4_q7.cpp。/树/主/第四章
  4. 这是一个实验室练习;不需要回答。

第五章

  1. 计算机内存可以描述为一个单一的概念——动态随机存取存储器(动态随机存取存储器)或计算机包含的所有内存单元的组合,从寄存器和高速缓冲存储器开始,到硬盘结束。从程序员的角度来看,DRAM 最受关注,因为它保存着计算机中运行的程序的指令和数据。
  2. 虚拟内存是一种有效管理计算机物理内存的方法。通常,操作系统结合虚拟内存来处理程序的内存访问,并有效地将内存块分配给特定的程序。
  3. 在 C++ 中,我们使用newdelete运算符来分配和释放内存空间。
  4. delete解除分配给单个对象的空间,而delete[]用于动态数组,并释放堆上数组的所有元素。
  5. 垃圾收集器是一种工具或一组工具和机制,用于在堆上自动释放资源。对于垃圾收集器,需要一个支持环境,例如虚拟机。C++ 直接编译成机器代码,无需支持环境即可运行。

第六章

  1. 当向向量中插入新元素时,它被放置在向量中已经分配的空闲槽中。如果向量的大小和它的容量相等,这意味着向量对于新元素没有空闲槽。在这些(罕见的)情况下,向量会自动调整自身大小,这包括分配新的内存空间,并将现有元素复制到新的更大的空间。
  2. 当在链表的前面插入一个元素时,我们只创建新元素并更新列表指针,以有效地将新元素放入列表中。在向量的前面插入一个新元素需要所有的向量元素向右移动,为该元素释放一个槽。
  3. 参考 GitHub 中的章节源代码。
  4. 它看起来像一个链表。
  5. 选择排序搜索最大(或最小)元素,并用该最大(或最小)元素替换当前元素。插入排序将集合分成两个部分,遍历未排序的部分,并将其每个元素放在排序部分的适当槽中。
  6. 参考 GitHub 中的章节源代码。

第七章

  1. C++ 中的 ranges 库允许处理元素的范围,使用视图适配器来操作它们,这要高效得多,因为它们不会将整个集合存储为适配器结果。
  2. 如果一个函数不修改状态,那么它就是纯函数,并且对相同的输入产生相同的结果。
  3. 纯虚函数是没有实现的函数的特征。纯虚函数用于描述派生类的接口函数。函数式编程中的纯函数是那些不修改状态的函数。
  4. 折叠(或简化)是将一组值组合在一起以生成数量减少的结果的过程。
  5. 尾部递归允许编译器通过省略为每个递归调用分配新的内存空间来优化递归调用。

第八章

  1. 如果两个操作的开始和结束时间在任意点交错,则两个操作同时运行。
  2. 并行性意味着任务同时运行,而并发性不会强制任务同时运行。
  3. 进程是程序的形象。它是加载到计算机内存中的程序指令和数据的组合。
  4. 线程是可由操作系统调度程序调度的进程范围内的一段代码,而进程是正在运行的程序的映像。
  5. 参考本章中的任何示例。
  6. 通过使用双重检查锁定。
  7. 请参考 GitHub 中章节的源代码。
  8. C++ 20 引入了 coroutines,作为对经典异步函数的补充。Coroutines 将代码的后台执行移动到下一个级别。它们允许功能在必要时暂停和恢复。co_await是告诉代码等待异步执行代码的构造。这意味着函数可以在该点暂停,并在结果准备好时恢复执行。

第九章

  1. 双重检查锁定是让 Singleton 模式在多线程环境中完美工作的一种方式。
  2. 这是一种确保在我们复制另一个堆栈的基础数据时不会被修改的方法。
  3. 原子操作是一个不可分割的操作,原子类型利用低级机制来确保指令的独立和原子执行。
  4. load()store()利用低级机制来确保写和读操作以原子方式完成。
  5. 除了load()store()外,还有exchange()wait()notify_one()等操作。

第十章

  1. TDD 代表测试驱动开发,目的是在项目实际实现之前编写测试。这有助于更清楚地定义项目需求,并提前避免代码中的大多数错误。
  2. 交互图描绘了对象通信的确切过程。这允许开发人员在任何给定的时刻对实际的程序执行有一个高层次的了解。
  3. 在聚合的情况下,包含其他类的一个或多个实例的类可以在没有聚合的情况下被实例化。另一方面,作文表达了强烈的遏制。
  4. 简单来说,李斯科夫替换原理确保了任何以某种类型的对象为参数的函数,如果 K 扩展了 T,也会以 K 类型的对象为参数。
  5. 开-闭原则规定类应该开放扩展,封闭修改。在所述的例子中,Animal是开放扩展的,所以从Animal继承monkey类并不违背原则。
  6. 参考 GitHub 中的章节源代码。

破产重组保护

  1. 重写私有虚函数允许通过保持公共接口不变来修改类的行为。
  2. 这是一种行为设计模式,其中一个对象封装了一个动作以及执行该动作所需的所有信息。
  3. 尽可能与其他对象共享数据。当我们有许多结构相似的对象时,跨对象共享重复的数据可以最大限度地减少内存的使用。
  4. 观察者向订阅者对象通知一个事件,而中介者在相互通信的对象之间扮演连接中枢的角色。
  5. 将游戏循环设计为无限循环是合理的,因为理论上,游戏可能永远不会结束,只有在玩家命令时才会结束。

第十二章

  1. 物理、数据链路、网络、传输、会话、演示和应用。
  2. 端口号提供了一种区分在同一环境中运行的多个网络应用的方法。
  3. 套接字是抽象概念,为程序员提供了通过网络发送和接收数据的方法。
  4. 首先,我们需要用一个 IP 地址创建并绑定套接字。接下来,我们应该监听传入的连接,如果有,我们应该接受该连接以进一步处理数据通信。
  5. TCP 是一种可靠的协议。它处理端点之间的强连接,还通过重新发送接收器未接收到的数据包来处理数据包丢失。另一方面,UDP 不可靠。几乎处理的每一个方面都落在程序员的肩上。UDP 的优势在于它的速度,因为它省略了握手、检查和数据包丢失处理。
  6. 宏定义会导致代码中难以发现的逻辑错误。用const表达式总比用宏好。
  7. 客户端应用必须具有唯一的标识符以及用于授权和/或认证它们的令牌(或密码)。

第十三章

  1. 这是一个实验室练习;不需要回答。
  2. 以下输出来自 NVIDIA Jetson Nano 上的 Ubuntu 18.04:
swu@swu-desktop:~/ch13$ g++ -c -Wall -Weffc++ -Wextra ch13_rca_compound.cpp
 ch13_rca_compound.cpp: In function ‘int main()’:
 ch13_rca_compound.cpp:11:17: warning: operation on ‘x’ may be undefined [-Wsequence-point]
 std::cout << f(++ x, x) << std::endl; //bad,f(4,4) or f(4,3)?
 ^~~
swu@swu-desktop:~/ch13$ g++ -c -Wall -Weffc++ -Wextra ch13_rca_mix_sign_unsigned.cpp
nothing is detected 
swu@swu-desktop:~/ch13$ g++ -c -Wall -Weffc++ -Wextra ch13_rca_order_of_evaluation.cpp
 ch13_rca_order_of_evaluation.cpp: In constructor ‘A::A(int)’:
 ch13_rca_order_of_evaluation.cpp:14:14: warning: ‘A::v3’ will be initialized after [-Wreorder]
 int v1, v2, v3;
 ^~
 ch13_rca_order_of_evaluation.cpp:14:6: warning: ‘int A::v1’ [-Wreorder]
 int v1, v2, v3;
 ^~
 ch13_rca_order_of_evaluation.cpp:7:2: warning: when initialized here [-Wreorder]
 A(int x) : v2(v1), v3(v2), v1(x) {
 ^
 ch13_rca_order_of_evaluation.cpp: In constructor ‘B::B(float)’:
 ch13_rca_order_of_evaluation.cpp:32:6: warning: ‘B::v2’ will be initialized after [-Wreorder]
 int v2;
 ^~
 ch13_rca_order_of_evaluation.cpp:31:6: warning: ‘int B::v1’ [-Wreorder]
 int v1; //good, here the declaration order is clear
 ^~
 ch13_rca_order_of_evaluation.cpp:25:2: warning: when initialized here [-Wreorder]
 B(float x) : v2(x), v1(v2) {};
 ^
 swu@swu-desktop:~/ch13$ g++ -c -Wall -Weffc++ -Wextra ch13_rca_uninit_variable.cpp
 ch13_rca_uninit_variable.cpp: In function ‘int main()’:
 ch13_rca_uninit_variable.cpp:7:2: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]
 if (x) {
 ^~
  1. 因为静态分析工具从它们的模型中预测错误,而动态分析工具通过程序的执行来检测错误。
  2. 请参考位于 的示例代码ch13_tdd_v3.hch13_tdd_v3.cppch13_tdd_Boost_UTF3.cpp。/树/主/第十三章

第十四章

  1. Qt 的编译模型允许省略虚拟机。它使用一个元对象编译器 ( MOC )翻译成 C++,然后编译成特定平台的机器码。
  2. QApplication::exec()是申请的起点。它启动 Qt 的事件循环。
  3. 通过调用setWindowTitle()
  4. m->index (2, 3)
  5. wgt->resize (400, 450)
  6. QLayout继承时,应该提供addItem()sizeHint()setGeometry()itemAt()takeAt()minimumSize()功能的实现。
  7. 通过使用connect()函数,该函数以源和目标对象以及信号和槽的名称作为参数。

第十五章

  1. ML 代表机器学习,是一个研究算法和统计模型的领域,计算机系统使用这些算法和统计模型来执行特定的任务,而不使用明确的指令,而是依靠模式和推理。
  2. 监督学习算法(也称为教师培训)从标记数据集学习;也就是说,每条记录都包含描述数据的附加信息。无监督学习算法甚至更复杂——它们处理包含一堆特征的数据集,然后试图找到特征的有用属性。
  3. ML 应用包括机器翻译、自然语言处理、计算机视觉和电子邮件垃圾检测。
  4. 方法之一是为每个结果增加一个权重,如果减法运算的权重超过其他运算,它将成为主导运算。
  5. 神经网络的目的是识别模式。

第十六章

  1. 爬虫下载网页并存储其内容,供搜索引擎索引。
  2. 我们称之为倒排索引,因为它将单词映射回它们在文档中的位置。
  3. 在索引之前,标记化将单词规范化。
  4. 推荐引擎验证并推荐适合特定请求的最佳结果。
  5. 知识图是其中节点是主题(知识)并且边是主题之间的连接的图。