[C++ Primer Reading Notes] Day 4

Scope

Chapter 2.5-2.6

Review

Chapter 2.5 introduces more facilities that can deal with types. They are required to obey the rules that applied to built-in types and compound types we have learned. Chapter 2.6 introduces how can we write a safe header file for our data structure.

Notes

1. definitions of type aliases

A type alias is a name that is a synonym for another type. Type aliases let us simplify complicated type definitions, making those types easier to use.

The first way to define a type alias is using a keyword typedef:

The keyword typedef may appear as part of the base type of a declaration. Declarations that include typedef define type aliases rather than variables.

typedef double wages;
typedef wage base, *p;  // base is a double, p is a double *

The second way to define alias is using alias declaration:

An alias declaration starts with the keyword using followed by the alias name and an =.

using SI = Sales_item;  // SI is a synonym for Sales_item

2. the using of pointers, const, and type aliases together

It can be tempting, albeit incorrect, to interpret a declaration that use a type alias by conceptually replacing the alias with its corresponding type.

For example,

typedef char *pstring;
const pstring cstr = 0;  // cstr is a const pointer
const pstring *ps;  // ps is pointer to a const pointer to char

For the second line, if we just conceptually replace “pstring” by “char *”, which makes the declaration looks like

const char *cstr = 0;

According to this incorrect understanding, cstr becomes a pointer to const, and “const char” becomes the base type of this declaration.

According to the C++ rules, we should take the alias name as a single type name. In this way, the
“const” is used to modify “pstring”, and the base type of this declaration is “pstring”. As a result, cstr is a const pointer.

3. the auto type specifier

we can let the compiler figure out the type for us by using the auto specifier.
auto tells the compiler to deduce the type from the initializer.

By implication, a variable that uses auto as its type specifier must have an initializer.

Because a declaration can involve only a single base type, the initializers for all the variables in the declaration must have types that are consistent with each other.
a reference or a printer is part of a particular declarator and not part of the base type for the declaration. As usual, the initializers must provide consistent auto-deduced types.

For example,

auto sz = 0, pi = 3.14;  

int i = 0;
const int ci = i;
auto &n = i, *p2 = &ci;

In the first line, the first initializer is int, but the second initializer is double or float, which is not consistent with the first one. It would lead to an error.

In the fourth line, the first initializer is int, but the seconde initializer is const int, which will cause an error too.

4. the using of compound types, const, and auto

There are two rules need to be careful when we use auto. The first one is

when we use a reference as an initializer, the initializer is the corresponding object. The compiler uses that object’s type for auto’s type deduction.

The second rule is

auto ordinarily ignores top-level consts. As usual in initializations, low-level consts, such as when an initializer is a pointer to const, are kept.

For example,

int i = 0, &r = i;
const int ci = i, &cr = ci;
auto c = cr;

In the third line, cr is a reference, but in this auto declaration, the object that cr refers to is used, that is a const int. This const is a top-level const, so the compiler would give the int type to variable c.

5. the decltype type specifier

Sometimes we want to define a variable with a type that the compiler deduces from an expression but do not want to use that expression to initialize the variable. For such case, the new standard introduced a second type specifier, decltype, which returns the type of its operand. The compiler analyzes the expression to determine its type but does not evaluate the expression.

That is to say, no matter what expression is written in the decltype declaration, the expression won’t be calculated or executed.

There are a few matters that should be noticed when using decltype:

It worth noting that decltype is the only context in which a variable defined as a reference it not treated as a synonym for the object to which it refers.

some expressions will cause decltype to yield a reference type. Generally speaking, decltype returns a reference type for expressions that yield objects that can stand on the left-hand side of the assignment
the dereference operator is an example of an expression for which decltype returns a reference.
When we apply decltype to a variable without any parentheses, we get the type of that variable. If we wrap the variable’s name in one or more sets of parentheses, the compiler will evaluate the operand as an expression (that yield objects that can stand on the left-hand side of the assignment). As a result, decltype on such an expression yields a reference.

For example,

int i = 42, *p = &i, &r = i;
decltype(r+0) b;  // int
decltype(*p) c = &i; // int&

decltype((i)) d = &i;  // int&
decltype(i) d;  // int

In the second line, r is a reference, so decltype® is a reference type. However, the result of the expression r+0 is an int. We can give variable b the same type as the object that r refers. r+0 is not an expression that yields an object that can stand on the left-hand side of the assignment. So decltype(r+0) won’t give variable b the reference type.

In the third line, “*p” is an expression that yield objects that can stand on the left-hand side of the assignment. Therefore, decltype(*p) would give variable c the reference type.

In the fourth line, “(i)” is an expression that yields an object that can stand on the left-hand side of the assignment, not a single variable, in this case, an lvalue expression, whose value is identical to the value of the variable i. (the definition of lvalue will be introduced in later chapters) Therefore, decltype((i)) gives variable d the reference type.

It should be noted that, in a decltype declaration, we have to give initializers to those which are definitly reference. This is a rule that all kinds of reference have to obey.

6. differences between auto and decltype

The functions of decltype and auto are similar. Both of them make the compiler deduce the type of a variable.

However, there are some differences between them

autodecltype
ignore the top-level const. when an initializer is a reference, the object that the reference refers to decide the typedecltype returns the type of that variable, including top-level const and references.
the expression in the initializer would be calculated when compilingthe expression given to decltype woun’t be calculated or executed when compiling
the expression is used as the initializerthe expression is used in a pair of parantheses which looks like the parameter of the decltype
initializer is a mustinitializer is not a must

7. using header files safely

programs that use Sales_data will include the string header twice: once directly and once as a side effect of including Sales_data.h. Because a header might be included more than once, we need to write our headers in a way that is safe even if the header is included multiple times.

I believe that many rules in C++ are created due to different kinds of problems. The rules are reasonable.

Here is the solution to headers being included multiple times: head guards, which relies on the preprocessor.

The preprocessor–which C++ inherits from C–is a program that runs before the compiler and changes the source text of our programs.
When the preprocessor sees a #include, it replaces the #include with the contents of the specified header.

That is to say, after preprocessing, all the #include in the program will be replaced by the contents in the .h file. During this procedure, the head guards in the .h files work.

Head guards rely on preprocessor variables. Preprocessor variables have one or two possible states: defined or not defined.
The #define directive takes a name and defines that name as a preprocessor variable.
There are two other directives that test whether a given preprocessor variable has or has not been defined: #ifdef and #ifndef. If the test is true, then everything following the #ifndef is processed up to the matching #endif.

For example,

#ifndef SALES_DATA_H  
#define SALES_DATA_H
#include <string>
struct Sales_data {
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};
#endif

The name of the preprocess variable is usually the uppercase version of the .h file name. It is recommended that every .h file has a header guard.

Extra Summaries

1. types that need an initializer

typereason
all referenceswe cannot rebind a reference to the second variable
all constthe value of all const variables cannot be changed
variable that uses auto as its type specifierthe compiler have to deduce the type from the initializer

2. the effect of const level in copying and initialization

No matter in copying or in initialization, the most important is :
low-level const matters more than top-level const.

In copying between two variables with different types, the top-level const can be ignored, but the low-level const decide whether this copying or conversion is legal or not.

In the initialization of an auto type, the top-level const of the initializer can be ignored, which means the top-level const feature won’t be passed to the new variable. Instead, the low-level const feature would be kept in the new variable.

Word List

type alias 类型别名
type specifier 类说明符
preprocessor 预处理器
head guard 头文件保护符

已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 在信息技术领域,特别是软件编程行业,微软公司推出的集成开发环境(IDE)Visual Studio,凭借其卓越的功能和广泛的适用范围,成为了众多程序员的常用工具。不过,在实际操作期间,用户可能会遭遇各种挑战,其中一种较为普遍的挑战是“Visual Studio遭遇了异常情况,这或许与某个附加组件有关”。本文将详细研究这一现象的成因、潜在后果以及最终的应对措施。 ### 原因剖析 Visual Studio通过支持多种插件和附加组件来扩展其功能,这些组件通常由第三方开发者设计,旨在为用户提供更多个性化和专业化的工具。然而,这些插件的质量良莠不齐,部分可能未经过充分的测试或与特定版本的Visual Studio存在兼容性难题,从而在执行时引发异常。异常的出现可能源于以下几个因素: 1. **代码缺陷**:若附加组件中的代码存在逻辑问题或资源管理不当,就可能导致运行时异常。 2. **资源竞争**:多个插件同时占用相同的资源(例如内存、文件句柄等),可能会产生资源冲突,进而触发异常。 3. **依赖不匹配**:插件可能需要特定版本的库或框架,如果系统中安装的版本不一致,也可能导致异常。 4. **安全隐患**:部分插件可能存在安全漏洞,一旦被恶意利用,可能会导致更严重的问题,包括但不限于异常崩溃。 ### 后果分析 当Visual Studio遇到由附加组件引发的异常时,不仅会中断当前的工作进程,降低开发效能,还可能带来以下潜在风险: 1. **数据遗失**:若异常发生在保存操作之前,可能会导致未保存的工作内容遗失。 2. **稳定性减弱**:频繁的异常会导致Visual Stud...
内容概要:本文围绕有源中点箝位(ANPC)三电平并网逆变器,提出并深入研究了一种融合双极性倍频脉宽调制(DPWMA)、正负序分离锁相控制与电网电压前馈控制的高性能一体化并网策略。研究首先系统分析了ANPC三电平逆变器在开关损耗均衡、中点电位稳定、输出谐波含量低等方面的拓扑结构优势,为实现高质量并网奠定了坚实的硬件基础。在此基础上,通过引入DPWMA调制策略,有效提升了等效开关频率,显著优化了输出电压电流的波形质量,降低了谐波畸变。为应对电网电压不平衡、畸变等复杂工况,研究采用了正负序分离锁相技术,实现了对电网正序和负序分量的精确分离与独立控制,从而保障了在非理想电网条件下的精准相位同步。同时,通过叠加电网电压前馈控制,构建了前馈-反馈复合控制体系,提前补偿电网扰动,极大地增强了系统的动态响应速度和抗干扰能力。最终,通过Simulink仿真平台对稳态、电网不平衡及动态扰动等多种工况进行了全面验证,结果表明该复合控制策略能显著提升并网系统的电能质量、稳定性和工况适应性,为新能源发电等大功率并网应用提供了先进的技术解决方案。; 适合人群:具备电力电子、自动控制理论或新能源并网技术等相关专业知识背景,从事相关领域科研或工程开发工作的研究人员,尤其适合高校研究生、青年教师及电力系统仿真与设计工程师。; 使用场景及目标:①应用于对电能质量要求严苛的大功率并网逆变器控制系统设计与优化;②解决电网电压不平衡、谐波畸变等复杂非理想工况下的并网稳定性与同步精度问题;③为ANPC三电平逆变器的先进控制策略开发与性能提升提供详尽的仿真验证方案和技术参考;④支持高水平科研论文的复现、学位论文的课题研究以及重大工程项目前期的技术预研与论证。; 阅读建议:建议读者结合文中详述的系统拓扑、控制架构图及仿真模型,循序渐进地理解各控制模块的设计原理与协同工作机制,重点关注DPWMA调制的实现细节、正负序分离的数学原理与实现方法,以及前馈控制的嵌入方式与参数整定策略,并通过仿真实验与传统控制策略进行对比分析,以深刻掌握该复合控制策略的性能优势与工程应用价值。
内容概要:本文围绕“爆破载荷参数”主题,基于UFC 3-340-02与TM 5-855-02标准,系统研究爆炸冲击波在空气中的传播规律及其压力效应的理论建模与数值仿真方法,并通过Matlab代码实现关键参数的计算与分析。研究聚焦于峰值超压、正压持续时间、冲量等核心爆炸参数的工程估算模型,结合经验公式与简化物理假设,构建适用于防护结构设计与毁伤评估的爆炸载荷输入模型。重点在于将复杂的爆炸物理过程转化为可编程的数学表达式,利用Matlab平台完成数据可视化、参数敏感性分析及多工况仿真对比,从而为军事防护工程、建筑抗爆设计等领域提供科学依据和技术支持。; 适合人群:具备一定Matlab编程能力与力学基础知识,从事安全工程、防护结构设计、爆炸力学、武器效应分析及相关领域的科研人员、工程师与高校研究生。; 使用场景及目标:①掌握UFC/TM标准中爆炸压力参数的工程计算原理与应用方法;②学习如何将爆炸力学理论模型转化为可执行的Matlab代码;③应用于爆炸载荷下结构动力响应仿真、毁伤效能评估、安全距离判定等科研与工程实践任务; 阅读建议:建议读者结合UFC 3-340-02原始文献进行对照学习,重点关注代码中物理公式的单位一致性与参数量纲处理,动手调试并扩展代码以深入理解爆炸波传播特性,并尝试将其应用于多因素耦合(如地形、障碍物)的实际场景仿真中。
已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 在iOS应用开发过程中,构建语音通信功能是一项普遍的应用需求,特别是在社交平台和即时消息软件中。本指南将阐释如何借助Speex音频压缩格式来设计一个基础的语音通信程序。Speex是一种专为语音设计的开源音频压缩方案,特别适用于低带宽的网络环境。 一、Speex音频压缩技术概述 Speex是一种无成本的、开放源代码的音频编解码方案,由Jean-Marc Valin首创,目前归属于Xiph.Org基金会旗下。其核心优势在于能够提供卓越的语音清晰度同时降低带宽的消耗,非常适合网络电话和实时交流场景。Speex支持多种压缩等级,使得开发者能够在音质与带宽使用之间进行灵活的调配。 二、在iOS平台中整合Speex 1. 获取资源:必须将Speex库纳入你的项目架构中。这可以通过CocoaPods实现,在Podfile文件中添加`pod speex`声明,随后执行`pod install`指令。 2. 导入头文件:在需要运用Speex的源代码部分,需要引入相关的头文件,例如`#import <speex/speex.h>`。 3. 启动和设置:初始化Speex的编码器和解码器实例,设定恰当的采样频率、比特率等配置参数。例如: ```objc SpeexBits bits; SpeexEncoder *encoder = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); //窄带模式 SpeexDecoder *decoder = speex_decoder_init(speex_lib_get_mode(SPEEX_MODE...
打开链接下载源码: https://pan.quark.cn/s/a4b39357ea24 STM32F407是一种采用ARM Cortex-M4内核的微控制器,在嵌入式系统开发领域具有广泛的应用。本文将详细研究如何运用STM32F407芯片达成SD卡模拟U盘的功能,并且结合FATFS文件系统以及HAL库进行深入分析。 我们必须熟悉FATFS文件系统。FATFS是由ChaN软件公司开发的一种轻量级文件系统解决方案,能够支持多种文件系统类型,例如FAT12、FAT16以及FAT32。该文件系统被设计成可以移植到多种嵌入式系统中,包括STM32系列的微控制器。FATFS使得在嵌入式设备上执行文件读写操作变得简便,用户能够执行文件建立、删除、读取和写入等多种操作。 HAL库(Hardware Abstraction Layer)是由STMicroelectronics推出的一种驱动层软件,用于STM32系列微控制器,它提供了一套标准化的API接口,简化了开发者与硬件之间的交互,降低了代码的复杂程度,提升了开发工作的效率。在我们的项目中,HAL库将用于SD卡的初始化以及数据传输等底层工作。 实现STM32F407 SD卡模拟U盘的重要步骤如下: 1. **硬件连接**:STM32F407一般通过SPI或SDIO接口与SD卡进行数据交换。确保SD卡的CS、MISO、MOSI和SCK引脚与STM32的对应引脚正确连接。 2. **HAL库配置**:在HAL库中,使用`HAL_SD_Init()`函数对SD卡进行初始化。依据硬件的配置设定SPI或SDIO的时钟、模式及其他相关参数。 3. **FATFS配置**:在工程中集成FATFS的源代码,设定相关的宏定义,如`FF_FS_R...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值