好记性不如烂笔头。

第六章

  • 标准库给出了静态断言,形式类似如下:
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. 查看Linux基本系统信息

    #! /bin/bash #The scripts will return the system infomation #return hostname and version infomation ...

  2. IDEA项目追踪快捷键

    1.查看某个方法在哪里被调用: 在方法上右键选择FindUsages: 快捷键,在方法上Ctrl+G 2.从Ctroller方法直接跳过接口找到实现类方法: 在方法上右键:选择GoTo>Impl ...

  3. 修改ubuntu终端显示目录和计算机名称(转)

    注意:使用方法:# PS1='自定义内容' 注意两边的单引号 示例: PS1='(\u@\H \d \t)\$' ------------------------------------------- ...

  4. java:Hibernate框架3(使用Myeclipse逆向工程生成实体和配置信息,hql语句各种查询(使用hibernate执行原生SQL语句,占位符和命名参数,封装Vo查询多个属性,聚合函数,链接查询,命名查询),Criteria)

    1.使用Myeclipse逆向工程生成实体和配置信息: 步骤1:配置MyEclipse Database Explorer: 步骤2:为项目添加hibernate的依赖: 此处打开后,点击next进入 ...

  5. 使用svctraceviewer查看WCF服务异常信息

    这两天遇到一个问题,调用一个WCF服务的时候,服务器端正常的返回了数据,但是客户端却遇到了一场 System.ServiceModel.CommunicationException: The unde ...

  6. 数据测试002:利用Jmeter推送测试数据(上)

    数据测试002:利用Jmeter推送测试数据(上) 刚才用Jmeter配置一下MySQL数据库花了点时间,好在最后都解决了,注意下面几个问题: 1)没有配置  “Cannot load JDBC dr ...

  7. Altera DDR2 IP核学习总结1-----------SRAM,DRAM

    SRAM,DRAM,SDRAM和DDR2这些芯片详解网上铺天盖地的各种资料都有,这里只是根据个人习惯做一下总结,方便记忆. 详细资料可以参考https://wenku.baidu.com/view/3 ...

  8. Autumn is deep, alas! I stand on the grass in the shadow of the evergreen trees.

    essence. n. 本质 flush.n. 脸红 v. 刷洗 initiate.v.开始 intrinsic.固执的 mainfest.a.显然的 intuition.n.直觉上的 refrain ...

  9. CF1187E Tree Painting【换根dp】

    题目传送门 题意 一棵$N$个节点的树,初始时所有的节点都是白色,第一次可以选择任意一个把它涂成黑色.接下来,只能把与黑色节点原来相连的白色节点涂成黑色(涂成黑色的点视为被删去,与其它节点不相连).每 ...

  10. Python pymysql对数据库的基础操作

    示例数据库名demo,表名info select * from info; 查看该表数据 +----+-------+--------+-----+---------------------+---- ...