C++ 程序设计语言
好记性不如烂笔头。
第六章
- 标准库给出了静态断言,形式类似如下:
stastic_assert(A,S);//当A不为true时,把S作为一条编译器错误信息输出
其最重要的用途是为泛型编程中作为形参的类型设置断言
- void有两个作用:1,作为函数的返回类型用以说明函数不返回任何实际的值。2,作为指针的基本类型部分以表明指针所指对象的类型未知。
- 在一些机器体系结构中,存放变量的字节必须保持一种良好的对齐方式,以便硬件在访问数据结构资源的时候足够高效。alignof()运算符返回实参表达式的对齐情况,例如:
auto ac = alignof('c');//char的对齐情况
auto al = alignof(); //int的对齐情况
在为实体命名时,应尽量让名字反应实体含义而非实现细节。在C++中,以下形式并不被建议使用,pcname作为某个char*的名字,或者icount作为某个int计数变量的名字。原因如下:
- 把类型信息加到名字中降低了程序的抽象水平,尤其不利于泛型编程。
- 编译器比程序员更擅长记录和追踪类型信息。
- 一旦改变某个名字的类型,所有都要改。
- 随着用到的类型越来越多,设计的缩写集越来越大,有时含糊不清,有时过于啰嗦。
- 初始化:
初始化的形式大概有4种:
X a1{v}; //C++11中提出
X a2 = {v}; //继承自C语言
X a3 = v; //继承自C语言
X a4(v);
以上4种形式的初始化,只有第一种不受限制使用。一般推荐使用{}方式初始化,使用{}初始化称之为列表初始化(list initialization),好处是防止窄化转换。这句话的意思是:如果一种整型(浮点型)不能存放下另一种整型(浮点型)的值,则后者不会被转化为前者。(另外,整型值不能转化为浮点型的值)。因此,没有特别的理由,最好使用{}进行初始化。
- 初始化器缺失时:
若是未指定初始化器,则全局变量,名字空间变量,局部static变量,和static成员会执行相应数据类型的列表{}初始化。对于局部变量,和自由存储上的对象(动态对象),除非它们位于用户自定义类型的默认构造函数中,否则,不会执行默认初始化。若相对内部局部变量或者new创建的内置类型的对象进行初始化,使用{}的形式,例如:
void ff()
{
int x{};
char buf[]{};
int* p{new int{}};
char*q {new char[]{}};
}
- 推断类型:
c++提供两种从表达式中推断数据类型的机制。1.auto根据对象的初始化器推断对象的数据类型。可能是变量,const或者constwxpt的类型。2.decltype(expr)推断的对象不是一个简单的初始化器,有可能是函数的返回类型或者类成员类型。
- 右值
当考虑对象的寻址,拷贝,移动等操作时,有两种属性很关键:
1.有身份(has identity):在程序中有对象的名称,或指向该对象的指针,或该对象的引用。这样我们就能判断两个对象是否相等,或者对象的值是否发生改变。
2. 可移动(is movable):能把对象的内容移动出来。
在上述2中属性的四种组合形式中,有3种需要C++语言规则精确的描述(没有身份又不能移动的对象不重要)。用m表示可移动,用i表示有身份,分类如下:
左值有身份,但不能移动;右值是允许执行移出操作的对象。
- 类型别名:
typedef void(*PtoF)(int); //等价于 “using PtoF = void(*)int;”
- 指针:
大多数机器支持逐字节访问内存,其他机器则是从字中抽取字节,很少有机器支持直接寻址到二进制位。能独立分配且用内置指针指向的最小单位位char类型的对象。(bool类型占用的内存空间至少与char类型一样)。如果想要把更小的值存的更紧密,可使用位逻辑操作,结构中的位域,或者bitset。
- void* :
指向未知类型的对象的指针。除了函数指针(Why)和指向类成员的指针(why 和 why2)外,指向其他任意类型对象的指针都能赋值给void*类型指针。两个void* 可以比较是否相等,还能显式的把他转化为其他类型。
函数指针转换会带来不可预知的风险。 member functions中则隐含了this指针。具体参考链接中说明。
- 字符串字面常量:
字符串字面常量的类型是“若干个const字符组成的字符数组”,“abcd”的类型是const char[5]。下述代码是不安全的:
char* p = "abcd"; //错误,但C++11之前被接受
p[] = "d"; //错误,试图为常量赋值
- 原始字符串:
当字符串中出现大量的反斜线和双引号,原始字符串就避免了转义字符中的反斜线的重复出现,避免了书写错误。
string s = R"(\w\\ww\\)"; //s的内容是 \w\\ww\\
string s = R"("strings")"; //s的内容是 “strings”
- 指针与const
一个指针牵涉到两个对象,即指针本身和所指向的对象。在指针声明中,前置const关键字将令所指的对象而非指针本身成为常量。若要指针本身成为常量,则需要用 *const 代替 * 。
char * s = "abcd"; const char * p = s; //指向的内容为常量,p是指向const char的指针 char *const p2 = s; //指针为常量, p2是指向char的const指针
技巧是:从右向左读。
- 右值引用:
非const左值引用的对象可以由用户写入内容。const左值引用的对象从用户角度来看是不可修改的。右值引用对应一个临时对象,用户可以修改这个对象,并且认为这个对象以后不会被用到了。参考链接。
- 返回值
下面两种返回值形式是一样的
string to_string(int a); //前置返回类型
auto to_string(int a) -> string; //后置返回类型
- 局部变量:
定义在函数内部的名字通常称为局部名字,当线程执行到该定义处,它们被初始化。除非我们把变量声明为static,否则函数每次调用都会拥有该变量的一份拷贝。相反,如果我们把局部变量声明为static,则函数的所有调用中将使用唯一的一份静态分配的对象,该对象在线程第一次到达的时候进行初始化。
static局部变量有一重要作用:它可以在函数的多次调用间维护一份公共的信息,而无须使用全局变量。如果使用了全局变量,则有可能会被其他不想关的函数访问甚至干扰。
递归的初始化一个局部static变量会产生未定义的结果。
- 重载函数
重载函数并不考虑返回值,其和作用域有着密切关系。基类和派生类的作用域不同,因此默认情况下基类函数和派生类函数不会发生重载。如果想要实现跨类作用域或者跨命名空间作用域的重载,应该使用using声明或者using指示。依赖于参数的查找也会导致跨名字空间重载。
- 前置与后置条件
函数调用时应遵循的约定称为"前置条件",函数返回时应遵循的条件称为“后置条件”。
- 函数指针
与数据对象类似,由函数体生成的代码也置于某块内存区域中,因此它也有自己的地址。函数指针并不能修改所指向的代码(与机器体系有关,于系统设计有关)。调用者只能对函数指针做两种操作:调用它或者获取它的地址。通过获取地址得到的指针能被用来调用该函数。
void error(string s) {/* ... */} void (*efct)(string); //指向函数的指针,该函数接受一个字符串参数 void f()
{
efct = &error; //efet 指向error
efct("error"); //通过efct调用error
}
编译器发现efct是函数指针,因此会调用它所指的函数。即,解引用函数指针时可用 * ,也可不用。同样,获取函数地址时可以用&,也可以不用:
void(*f1)(string) = &error; //OK: 等价于 = error
void(*f2)(string) = error; //OK: 等价于 = &error void g()
{
f1("Vasa"); //OK: 等价于(*f1)("Vasa")
(*f1)("Mary Rose"); //OK: 等价于f1("Mary Rose")
}
函数指针的参数类型声明与函数本身类似,进行指针赋值操作时,要求完整的函数类型都必须精确匹配。
C++允许把一个函数指针类型转换成别的函数指针类型,但之后必须把得到的结果指针转换为其原来的类型,否则会出现意外情况:
using p1 = int(*)(int*);
using p2 = void(*)(void); void f(p1 pf)
{
p2 pf2 = reinterpret_cast<p2>(pf);
pf2(); //可能会出现严重错误
p1 pf1 = reinterpret_cast<p1>(pf2); //把pf2 转换回来
int x = ;
int y = pf1(&x);
//...
}
- 异常处理:
函数如果希望处理某个问题,可以捕获相应的异常:
1 主调组件如果想处理某些失败的情形,可以把这些异常置于try块的catch从句中。
2 被调组件如果无法完成既定的任务,可以用throw表达式抛出一个异常来说明这一情况。
void taskmaster()
{
try{
auto result = do_task();
//使用result
}
catch(Some_error)
{
//执行do_task时发生错误:处理该错误
}
} int do_task()
{
//...
if(/*能够执行该任务*/)
return result;
else
throw Some_error;
}
成功的容错系统都是多层级的。按照自底而上的顺序,每一层级在它力所能及的范围内处理更多的错误,把剩下的错误留给更高层级处理。
C++ 程序设计语言的更多相关文章
- 操作系统和程序设计语言的API使用的字符编码分析
1.Java的运行环境中,String是什么编码? 使用java做程序设计语言,字符编码是和jvm相关的,和操作系统无关. java默认的编码是jvm在安装的时候就确定了的,它是根据你的系统的环境确 ...
- python程序设计语言笔记 第一部分 程序设计基础
1.1.1中央处理器(CPU) cpu是计算机的大脑,它从内存中获取指令然后执行这些指令,CPU通常由控制单元和逻辑单元组成. 控制单元用来控制和协调除cpu之外的其他组件的动作. 算数单元用来完成数 ...
- 扩展《C程序设计语言》练习2-3程序通用性
最近开始自学C语言,在看K&R的<C程序设计语言>.练习2-3要求写一个函数,将输入的十六进制数字字符串转换成与之等价的整数值,配套答案没有扩展程序的通用性,所以我就稍微改造改造. ...
- 清风注解-Swift程序设计语言:Point11~15
目录索引 清风注解-Swift程序设计语言 Point 11. 数值型字面量 代码事例: let decimalInteger = // 十进制的17 let binaryInteger = 0b10 ...
- 清风注解-Swift程序设计语言:Point6~10
目录索引 清风注解-Swift程序设计语言 Point 6. 输出常量和变量 代码事例: // 输出的内容会在最后换行 println("hello, world") // 输出的 ...
- 清风注解-Swift程序设计语言:Point1~5
目录索引 清风注解-Swift程序设计语言 Point 1. Swift 风格的"Hello, world" 代码事例: println("Hello, world&qu ...
- 清风注解-Swift程序设计语言
前言 Apple 发布了全新的 Swift 程序设计语言,用来开发 iOS 和 OS X 平台的应用程序.其目的不言而喻:就是为了给老迈的 Objective-C 一个合适接班人!因此,不难预见,未来 ...
- C程序设计语言(第二版)习题:第一章
第一章虽然感觉不像是个习题.但是我还是认真去做,去想,仅此而已! 练习 1-1 Run the "hello, world" program on your system. Exp ...
- Oberon程序设计语言简介
Oberon奥伯龙是一种通用编程语言,也是一种同名操作系统(由Oberon语言开发,且参考过贝尔实验室的新一代网络操作系统Plan9),是由原Pascal程序设计语言的发明者Niklaus Wirth ...
- awk程序设计语言之-awk基础
awk程序设计语言之-awk基础 http://man.linuxde.net/ 常用工具命令之awk命令 awk是一种编程语言,用于在Linux/Unix下对文本和数据处理.数据可以来自标准输入(s ...
随机推荐
- https的那些坑
1.时间 一些老手机不是系统自动对时,时间错误会报错. com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeExceptio ...
- Oracle_Windows server ORA-01031: insufficient privileges
PS C:\Users\admin> sqlplus / as sysdba SQL*Plus: Release 11.2.0.1.0 Production on 星期二 9月 3 10:21: ...
- DP练习题——洛谷P1970花匠
目录 题目描述: 输入输出格式: 输入格式: 输出格式: 输入输出样例: 输入样例: 输出样例: 题目分析: 解法一: 解法二: 结语: 题目描述: 洛谷\(P1970\) 花匠栋栋种了一排花,每株花 ...
- deepClone deepCompare
一.深度复制 // 深度复制 function deepClone(datas) { if (typeof datas !== 'object' || datas === null) return d ...
- leetcode 115不同的子序列
滚动数组: /***** 下标从1开始 dp[i][j]:= numbers of subseq of S[1:j] equals T[1:i] if(s[j]==t[i]):(那么之后的子串可以是是 ...
- Git检出和提交至远程仓库
步骤一:首先需要一个Github账号,还没有的话先去注册:https://github.com/,我们使用Git需要先安装Git工具,这里给出下载地址:https://git-for-windows. ...
- android 面试汇总<一>
1.1 Android Activity Q:说下Activity的生命周期? 技术点:Activity生命周期 思路:分条解释Activity从创建到销毁整个生命周期中涉及到的方法及作用 参考回答: ...
- block(块级元素)和 inline(内联元素) 的区别
block(块级元素)和 inline(内联元素) 的区别 (2009-01-05 10:32:07) 转载▼ 标签: 杂谈 分类: div+css div这样的块级元素,就会自动占据一定矩形空间,可 ...
- sun.misc.BASE64Encoder 不建议使用java.sun自带包中的内容
import sun.misc.BASE64Decoder; 在项目中,设计到64位编码的.有时开发会用到JDK中自带的BASE64工具.但sun公司是建议不这样做的.尤其是更新了JDK版本,项目甚至 ...
- Java String.Format() 方法及参数说明
转自:https://blueram.iteye.com/blog/441683 JDK1.5中,String类新增了一个很有用的静态方法String.format():format(Locale l ...