好记性不如烂笔头。

第六章

  • 标准库给出了静态断言,形式类似如下:
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计数变量的名字。原因如下:

  1. 把类型信息加到名字中降低了程序的抽象水平,尤其不利于泛型编程。
  2. 编译器比程序员更擅长记录和追踪类型信息。
  3. 一旦改变某个名字的类型,所有都要改。
  4. 随着用到的类型越来越多,设计的缩写集越来越大,有时含糊不清,有时过于啰嗦。
  • 初始化:

  初始化的形式大概有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++ 程序设计语言的更多相关文章

  1. 操作系统和程序设计语言的API使用的字符编码分析

     1.Java的运行环境中,String是什么编码? 使用java做程序设计语言,字符编码是和jvm相关的,和操作系统无关. java默认的编码是jvm在安装的时候就确定了的,它是根据你的系统的环境确 ...

  2. python程序设计语言笔记 第一部分 程序设计基础

    1.1.1中央处理器(CPU) cpu是计算机的大脑,它从内存中获取指令然后执行这些指令,CPU通常由控制单元和逻辑单元组成. 控制单元用来控制和协调除cpu之外的其他组件的动作. 算数单元用来完成数 ...

  3. 扩展《C程序设计语言》练习2-3程序通用性

    最近开始自学C语言,在看K&R的<C程序设计语言>.练习2-3要求写一个函数,将输入的十六进制数字字符串转换成与之等价的整数值,配套答案没有扩展程序的通用性,所以我就稍微改造改造. ...

  4. 清风注解-Swift程序设计语言:Point11~15

    目录索引 清风注解-Swift程序设计语言 Point 11. 数值型字面量 代码事例: let decimalInteger = // 十进制的17 let binaryInteger = 0b10 ...

  5. 清风注解-Swift程序设计语言:Point6~10

    目录索引 清风注解-Swift程序设计语言 Point 6. 输出常量和变量 代码事例: // 输出的内容会在最后换行 println("hello, world") // 输出的 ...

  6. 清风注解-Swift程序设计语言:Point1~5

    目录索引 清风注解-Swift程序设计语言 Point 1. Swift 风格的"Hello, world" 代码事例: println("Hello, world&qu ...

  7. 清风注解-Swift程序设计语言

    前言 Apple 发布了全新的 Swift 程序设计语言,用来开发 iOS 和 OS X 平台的应用程序.其目的不言而喻:就是为了给老迈的 Objective-C 一个合适接班人!因此,不难预见,未来 ...

  8. C程序设计语言(第二版)习题:第一章

    第一章虽然感觉不像是个习题.但是我还是认真去做,去想,仅此而已! 练习 1-1 Run the "hello, world" program on your system. Exp ...

  9. Oberon程序设计语言简介

    Oberon奥伯龙是一种通用编程语言,也是一种同名操作系统(由Oberon语言开发,且参考过贝尔实验室的新一代网络操作系统Plan9),是由原Pascal程序设计语言的发明者Niklaus Wirth ...

  10. awk程序设计语言之-awk基础

    awk程序设计语言之-awk基础 http://man.linuxde.net/ 常用工具命令之awk命令 awk是一种编程语言,用于在Linux/Unix下对文本和数据处理.数据可以来自标准输入(s ...

随机推荐

  1. https的那些坑

    1.时间 一些老手机不是系统自动对时,时间错误会报错. com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeExceptio ...

  2. 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: ...

  3. DP练习题——洛谷P1970花匠

    目录 题目描述: 输入输出格式: 输入格式: 输出格式: 输入输出样例: 输入样例: 输出样例: 题目分析: 解法一: 解法二: 结语: 题目描述: 洛谷\(P1970\) 花匠栋栋种了一排花,每株花 ...

  4. deepClone deepCompare

    一.深度复制 // 深度复制 function deepClone(datas) { if (typeof datas !== 'object' || datas === null) return d ...

  5. leetcode 115不同的子序列

    滚动数组: /***** 下标从1开始 dp[i][j]:= numbers of subseq of S[1:j] equals T[1:i] if(s[j]==t[i]):(那么之后的子串可以是是 ...

  6. Git检出和提交至远程仓库

    步骤一:首先需要一个Github账号,还没有的话先去注册:https://github.com/,我们使用Git需要先安装Git工具,这里给出下载地址:https://git-for-windows. ...

  7. android 面试汇总<一>

    1.1 Android Activity Q:说下Activity的生命周期? 技术点:Activity生命周期 思路:分条解释Activity从创建到销毁整个生命周期中涉及到的方法及作用 参考回答: ...

  8. block(块级元素)和 inline(内联元素) 的区别

    block(块级元素)和 inline(内联元素) 的区别 (2009-01-05 10:32:07) 转载▼ 标签: 杂谈 分类: div+css div这样的块级元素,就会自动占据一定矩形空间,可 ...

  9. sun.misc.BASE64Encoder 不建议使用java.sun自带包中的内容

    import sun.misc.BASE64Decoder; 在项目中,设计到64位编码的.有时开发会用到JDK中自带的BASE64工具.但sun公司是建议不这样做的.尤其是更新了JDK版本,项目甚至 ...

  10. Java String.Format() 方法及参数说明

    转自:https://blueram.iteye.com/blog/441683 JDK1.5中,String类新增了一个很有用的静态方法String.format():format(Locale l ...