
C++ Primer学习笔记
「已注销」
这个作者很懒,什么都没留下…
展开
-
转发参数包
在新标准下,我们可以组合使用可变参数模板与forward机制来编写函数,实现将其实参不变地传递给其他函数。原创 2015-04-28 22:19:27 · 875 阅读 · 0 评论 -
格式化输入与输出
除了条件状态外,每个iostream对象还维护了一个格式状态来控制IO如何格式化的细节。 标准库定义了一组操纵符(manipulator)来修改流的格式状态。一个操纵衔是一个函数或是一个对象,会影响流的状态,并能用作输入或输出运算符的运算对象。类似输入和输出运算符,操纵符也返回它所处理的流对象,因此我们可以在一条语句中组合操纵符和数据。很多操纵符改变格式状态 操纵符用于两大类输出控制:控制数值的原创 2015-05-02 17:40:27 · 535 阅读 · 0 评论 -
引用折叠和右值引用参数
通常我们不能将一个右值引用绑定到一个左值上。但是,C++语言在正常的绑定规则之外定义了两个例外规则: 第一个例外规则影响右值引用参数的推断如何进行。当我们将一个左值传递给函数的右值引用参数,且此右值引用指向模板类型参数(如T&&)时,编译器推断模板类型参数为实参的左值引用类型。 第二个例外绑定规则:如果我们间接创建一个引用的引用,则这些引用形成了“折叠”。在所有情况下(除了一个例外),引用会折叠原创 2015-04-28 11:19:51 · 1216 阅读 · 0 评论 -
函数try语句块与构造函数
要想处理构造函数初始值抛出的异常,我们必须将构造函数写成函数try语句块(function try block)的形式。函数try语句块使得一组catch语句既能处理构造函数体(或析构函数体),也能处理构造函数的初始化过程(或析构函数的析构过程)。template <typename T>Blob<T>::Blob(std::initializer_list il) try : data(std原创 2015-05-03 22:00:10 · 1917 阅读 · 0 评论 -
函数指针与实参推断
当我们用一个函数模板初始化一个函数指针或为一个函数指针赋值时,编译器使用指针的类型来推断模板实参。template <typename T> int compare(const T&, const T&);// pf1指向实例int compare(const int&, const int&)int (*pf1)(const int&, const int&) = compare;pf1中参数原创 2015-04-28 10:33:16 · 348 阅读 · 0 评论 -
理解std::move
std::move是如何定义的 标准库是这样定义move的:// 在返回类型和类型转换中也要用到typenametemplate <typename T>typename remove_reference<T>::type&& move(T&& t){ return static_cast<typename remove_reference<T>::type&&>(t);}从一个左原创 2015-04-28 14:20:07 · 807 阅读 · 1 评论 -
异常处理
异常处理(exception handling)机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并做出相应的处理。异常使得我们能够将问题的检测与解决过程分离开来。程序的一部分负责检测问题的出现,然后解决该问题的任务传递给程序的另一部分。检测环节无须知道问题处理模块的所有细节,反之亦然。抛出异常 在C++语言中,我们通过抛出(throwing)一条表达式来引发(raised)一个异常。被原创 2015-05-03 20:49:31 · 524 阅读 · 0 评论 -
未格式化的输入/输出操作
标准库提供了一组低层操作,支持未格式化IO(unformatted IO)。这些操作允许我们将一个流当作一个无解释的字节序列来处理。一般情况下,在读取下一个值之前,标准库保证我们可以退回最多一个值。即,标准库不保证在中间不进行读取操作的情况下能连续调用putback或unget。确定读取了多少个字符 某些操作从输入读取未知个数的字节。我们可以调用gcount来确定最后一个未格式化输入操作读取了多少原创 2015-05-03 11:11:53 · 452 阅读 · 0 评论 -
流随机访问
随机IO本质上是依赖于系统的。为了理解如何使用这些特性,你必须查询系统文档。 虽然标准库为所有流类型都定义了seek和tell函数,但它们是否会做有意义的事情依赖于流绑定到哪个设备。seek和tell函数 为了支持随机访问,IO类型维护一个标记来确定下一个读写操作要在哪里进行。它们还提供了两个函数:一个函数通过将标记*seek到一个给定位置来重定位它;另一个函数tell我们标记*的当前位置。只有原创 2015-05-03 11:35:10 · 462 阅读 · 0 评论 -
模板实参推断
对于函数模板,编译器利用调用中的函数实参来确定其模板参数。从函数实参来确定模板实参的过程被称为模板实参推断(template argument deduction)。在模板实参推断过程中,编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配。类型转换与模板类型参数 如果一个函数形参的类型使用了模板类型参数,那么它采用特殊的初始化规则。只有很有限的几种类原创 2015-04-28 09:59:41 · 925 阅读 · 0 评论 -
转发
某些函数需要将其一个或多个实参连同类型不变地转发给其他函数。在此情况下,我们需要保持被转发实参的所有性质,包括实参类型是否是const的以及实参是左值还是右值。定义能保持类型信息的函数参数 通过将一个函数参数定义为一个指向模板类型参数的右值引用,我们可以保持其对应实参的所有类型信息。而使用引用参数(无论是左值还是右值)使得我们可以保持const属性,因为在引用类型中的const是底层的。如果一个函原创 2015-04-28 16:23:47 · 348 阅读 · 0 评论 -
类型转换
进行类型转换的标准库模板类 标准库的类型转换模板定义在头文件type_traits中。这个头文件中的类通常用于所谓的模板元程序设计。 remove_reference模板有一个模板类型参数和一个名为type的(public)类型成员。如果我们用一个引用类型实例化remove_reference,则type将表示被引用的类型。例如,如果我们实例化remove_reference原创 2015-04-28 10:22:27 · 251 阅读 · 0 评论 -
使用regex_replace
替换字符串由我们想要的字符组合与匹配的子串对应的子表达式而组成。我们用一个符号$后跟子表达式的索引号来表示一个特定的子表达式。原创 2015-05-02 10:00:14 · 439 阅读 · 0 评论 -
类模板
类模板(class template)是用来生成类的蓝图的。与函数模板不同的是,编译器不能为类模板推断模板参数类型。实例化类模板 当使用一个类模板时,我们必须提供额外信息。我们现在知道这些额外信息是显式模板实参(explicit template argument)列表,它们被绑定到模板参数。编译器使用这些模板实参来实例化出特定的类。在模板作用域中引用模板类型 类模板的名字不是一个类型原创 2015-04-26 22:01:54 · 649 阅读 · 0 评论 -
匹配与Regex迭代器类型
1. sregex_iterator it(b, e, r);一个sregex_iterator,遍历迭代器b和e表示的string。它调用regex_search(b, e, m, r)将it定位到输入序列中第一个匹配的位置。2. sregex_iterator end;sregex_iterator的尾后迭代器。3. *it it->根据最后一个调用regex_search的结原创 2015-05-01 19:07:09 · 270 阅读 · 0 评论 -
成员模板
一个类(无论是普通类还是类模板)可以包含本身是模板的成员函数。这种成员被称为成员模板(member template)。成员模板不能是虚函数。普通(非模板)类的成员模板类模板的成员成员模板 对于类模板,我们也可以为其定义成员模板。在此情况下,类和成员各自有自己的、独立的模板参数。 与类模板的普通函数成员不同,成员模板是函数模板。当我们在类模板外定义一个成员模板时,必须同时为类模板和成员模板提供模原创 2015-04-27 17:14:10 · 304 阅读 · 0 评论 -
模板参数
模板参数与作用域 模板参数遵循普通的作用域规则。一个模板参数名的可用范围是在其声明之后,至模板声明或定义结束之前。与任何其他名字一样,模板参数会隐藏外层作用域中声明的相同名字。但是,与大多数其他上下文不同,在模板内不能重用模板参数名。 由于参数名不能重用,所以一个模板参数名在一个特定模板参数列表中只能出现一次。模板声明 模板声明必须包含模板参数。与函数参数相同,声明中的模板参数的名字不必与定义原创 2015-04-27 15:35:55 · 2645 阅读 · 0 评论 -
随机数
随机数引擎类(random-number engines)和随机数分布类(random-number distribution) 一个引擎类可以生成unsigned随机序列,一个分布类使用一个引擎类生成指定类型的、在给定范围内的、服从概率分布的随机数。随机数引擎和分布 随机数引擎是函数对象类,它们定义了一个调用运算符,该运算符不接受参数并返回一个随机unsigned整数。我们可以通过调用一原创 2015-05-02 11:39:54 · 686 阅读 · 0 评论 -
控制实例化
当模板被使用时才会进行实例化,这一特性意味着,相同的实例可能出现在多个对象文件中。当两个或多个独立编译的源文件使用了相同的模板,并提供了相同的模板参数时,每个文件中都会有该模板的一个实例。 在大系统中,在多个文件中实例化相同模板的额外开销可能非常严重。在新标准中,我们可以通过显式实例化(explicit instantiation)来避免这种开销。显式实例化有如下形式:// 实例化声明exte原创 2015-04-27 19:53:59 · 948 阅读 · 0 评论 -
捕获异常
catch子句(catch clause)中的异常声明(exception declaration)看起来像是只包含一个形参的函数形参列表。声明的类型决定了处理代码所能捕获的异常类型。这个类型必须是完全类型,它可以是左值引用,但不能是右值引用。查找匹配的处理代码 与实参和形参的匹配规则相比, 异常和catch异常声明的匹配规则受到更多的限制。此时,绝大多数类型转换都不被允许,除了一些极细小的差别之原创 2015-05-03 21:33:35 · 1044 阅读 · 0 评论 -
编写可变参数函数模板
我们可以使用一个initializer_list来定义一个可接受可变数目实参的函数。但是,所有实参必须具有相同的类型(或它们的类型可以转换为同一个公共类型)。可变参数函数通常是递归的。第一步调用处理包中的第一个实参,然后用剩余实参调用自身。// 用来终止递归并打印最后一个元素的函数// 此函数必须在可变参数版本的print定义之前声明template <typename T>ostream&原创 2015-04-28 21:19:14 · 1193 阅读 · 0 评论 -
可变参数模板
一个可变参数模板就是一个接受可变数目参数的模板函数或模板类。可变数目的参数被称为参数包(parameter packet)。存在两种参数包:模板参数包(template parameter packet),表示零个或多个模板参数;函数参数包(function parameter packet),表示零个或多个函数参数。 我们使用一个省略号来指出一个模板参数或函数参数表示的是一个参数包。在一个原创 2015-04-28 17:30:15 · 455 阅读 · 0 评论 -
枚举类型
C++包含两种枚举:限定作用域的和不限定作用域的。C++11新标准引入了限定作用域的枚举类型(scoped enumeration)。定义限定作用域的枚举类型一般形式是:首先是关键字enum class(或者等价地使用enum struct),随后是枚举类型名字以及用花括号括起来的以逗号分隔的枚举成员(enumerator)列表,最后是一个分号:enum class open_modes { inp原创 2015-05-05 16:52:42 · 425 阅读 · 0 评论 -
多重继承下的类作用域
在只有一个基类的情况下,派生类的作用域嵌套在直接基类和间接基类的作用域中。查找过程沿着继承体系自底向上进行,直到找到所需的名字。派生类的名字将隐藏基类的同名成员。 大多重继承的情况下,相同的查找过程在所有直接基类中同时进行。如果名字在多个基类中都被找到,则对该名字的使用将具有二义性。当一个类拥有多个基类时,有可能出现派生类从两个或更多基类中继承了同名成员的情况。此时,不加前缀限定符直接使用该名字将原创 2015-05-05 09:23:55 · 489 阅读 · 0 评论 -
new表达式与operator new函数
标准库函数operator new和operator delete的名字容易让人误解。和其他operator函数不同(比如operator=),这两个函数并没有重载new表达式或delete表达式。实际上,我们根本无法自定义new表达式或delete表达式的行为。 一条new表达式的执行过程总是先调用operator new函数以获取内存空间,然后在得到的内存空间中构造对象。与之相反,一条dele原创 2015-05-05 11:19:07 · 1254 阅读 · 0 评论 -
运行时类型识别
运行时类型识别(runtime type identification, RTTI)的功能由两个运算符实现: 1. typeid运算符,用于返回表达式的类型。 2. dynamic_cast运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用。dynamic_cast运算符 dynamic_cast运算符的使用形式如下所示:dynamic_cast<type*>(e);dynamic原创 2015-05-05 16:28:36 · 676 阅读 · 0 评论 -
union:一种节省空间的类
当我们给union的某个成员赋值之后,该union的其他成员就变成未定义的状态了。分配给一个union对象的存储空间至少要能容纳它的最大的数据成员。 union不能含有引用类型的成员,除此之外,它的成员可以是绝大多数类型。在C++11新标准中,含有构造函数或析构函数的类类型也可以作为union的成员类型。为union的一个数据成员赋值会令其他数据成员变成未定义的状态。含有类类型成员的union原创 2015-05-06 15:24:14 · 1046 阅读 · 0 评论 -
固有的不可移植的特性
为了支持低层编程,C++定义了一些固有的不可移植(nonportable)的特性。位域 类可以将其(非静态)数据成员定义成位域(bit-field),在一个位域中含有一定数量的二进制位。位域在内存中的布局是与机器相关的。位域的类型必须是整型或枚举类型。二进制位是否能压缩到一个整数中以及如何压缩是与机器相关的。 取地址运算符(&)不能作用于位域,因此任何指针都无法指向类的位域。通常情况下最好将位域原创 2015-05-06 16:59:09 · 606 阅读 · 0 评论 -
嵌套类
一个类可以定义在另一个类的内部,前者称为嵌套类(nested class)或嵌套类型(nested type)。嵌套类常用于定义作用实现部分的类。 嵌套类是一个独立的类,与外层类基本没什么关系。特别是,外层类的对象和嵌套类的对象是相互独立的。在嵌套类的对象中不包含任何外层类定义的成员;类似的,在外层类的对象中也不包含任何嵌套类定义的成员。外层类对嵌套类的成员没有特殊的访问权限,同样,嵌套类对外层类原创 2015-05-06 11:08:21 · 477 阅读 · 0 评论 -
匹配与Regex迭代器类型
1. sregex_iterator it(b, e, r);一个sregex_iterator,遍历迭代器b和e表示的string。它调用regex_search(b, e, m, r)将it定位到输入序列中第一个匹配的位置。2. sregex_iterator end;sregex_iterator的尾后迭代器。3. *it it->根据最后一个调用regex_search的结果原创 2015-05-01 20:49:57 · 317 阅读 · 0 评论 -
使用子表达式
正则表达式中的模式通常包含一个或多个子表达式(subexpression)。一个子表达式是模式的一部分,本身也具有意义。正则表达式语法通常用括号表示子表达式。匹配对象除了提供匹配整体的相关信息之外,还提供访问模式中每个子表达式的能力。子匹配是按位置来访问的。第一个子匹配位置为0,表示整个模式对应的匹配,随后是每个子表达式对应的匹配。子表达式用于数据验证 子表达式的一个常见用途是验证必须匹配特定格式原创 2015-05-01 21:26:24 · 419 阅读 · 0 评论 -
正则表达式类和输入序列类型
我们可以搜索多种类型的输入序列。输入可以是普通char数据或wchar_t数据,字符可以保存在标准库string中或是char数组中(或是宽字符版本,wstring或wchar_t数组中)。RE为这些不同的输入序列都定义了对应的类型。 例如,regex类保存类型char的正则表达式。标准库还定义了一个wregex类保存类型wchar_t,其操作与regex完全相同。两者唯一的差别是wregex的初原创 2015-05-01 16:32:46 · 734 阅读 · 0 评论 -
重载与模板
函数模板可以被另一个模板或一个普通非模板函数重载。与往常一样,名字相同的函数必须具有不同数量或类型的参数。 1。对于一个调用,其候选函数包括所有模板实参推断成功的函数模板实例。 2。候选的函数模板总是可行的,因为模板实参推断会排除任何不可行的模板。 3。与往常一样,可行函数(模板与非模板)按类型转换(如果对此调用需要的话)来排序。当然,可以用于函数模板调用的类型转换是非常有限的。 4。与往常原创 2015-04-28 17:02:45 · 429 阅读 · 0 评论 -
包扩展
对于一个参数包(模板参数包,函数参数包),除了获取其大小外,我们能对它做的唯一的事情就是扩展(expand)它。当扩展一个包时,我们还要提供用于每个扩展元素的模式(pattern)。扩展一个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表。我们通过在模式右边放一个省略号(…)来触发扩展操作。(省略号之前是模式)。扩展中的模式会独立地应用于包中的每个元素。原创 2015-04-28 21:55:19 · 593 阅读 · 0 评论 -
noexcept异常说明
在C++11新标准中,我们可以通过提供noexcept说明(noexcept specification)指定某个函数不会抛出异常。其形式是关键字noexcept紧跟在函数的参数列表后面,用以标识函数不会抛出异常:void recoup(int) noexcept; // 不会抛出异常void alloc(int); // 可能抛出异常对于一个函数来说,noexcep原创 2015-05-03 22:08:51 · 3386 阅读 · 0 评论 -
命名空间
命名空间为防止名字冲突提供了更加可控的机制。命名空间分割了全局命名空间,其中每个命名空间是一个作用域。命名空间定义 一个命名空间的定义包含两部分:首先是关键字namespace,随后是命名空间的名字。在命名空间名字后面是一系列由花括号括起来的声明和定义。只要能出现在全局作用域中的声明就能置于命名空间中。每个命名空间都是一个作用域 命名空间中的每个名字都必须表示该空间内的唯一实体。定义在某个命名空原创 2015-05-04 11:30:07 · 699 阅读 · 0 评论 -
友元声明与实参相关的查找
当类声明了一个友元时,该友元声明并没有使得友元本身可见。然而,一个另外的未声明的类或函数如果第一次出现在友元声明中,则我们认为它是最近的外层命名空间的成员。这条规则与实参相关的查找规则结合在一起将产生意想不到的效果:namespace{ class C { // 两个友元,在友元声明之外没有其他的声明 // 这些函数隐式地成为命名空间A的成员 friend原创 2015-05-04 17:23:57 · 573 阅读 · 0 评论 -
重载与命名空间
与实参相关的查找与重载 对于接受类类型实参的函数来说,其名字查找将在实参类所属的命名空间中进行。这条规则对于我们如何确定候选函数集同样也有影响。我们将在每个实参类(以及实参类的基类)所属的命名空间中搜寻候选函数。在这些命名空间中所有与被调用函数同名的函数都将被添加到候选集当中,即使其中某些函数在调用语句处不可见也是如此。重载与using声明 using声明语句声明的是一个名字,而不是一个特定的函原创 2015-05-04 20:22:47 · 429 阅读 · 0 评论 -
实参相关的查找与类类型
对于命名空间中名字的隐藏规则来说有一个重要的例外。这个例外是,当我们给函数传递一个类类型的对象时,除了在常规的作用域查找外还会查找实参类所属的命名空间。这一例外对于传递类的引用或指针的调用同样有效。 查找规则的这个例外允许概念上作为类接口一部分的非成员函数无须单独的using声明(using declaration)就能被程序使用。原创 2015-05-04 16:35:47 · 519 阅读 · 0 评论 -
多重继承
对于派生类能够继承的基类个数,C++没有进行特殊规定:但是在某个给定的派生列表中,同一个基类只能出现一次。派生类构造函数初始化所有基类 构造一个派生类的对象将同时构造并初始化它的所有基类子对象。派生类的构造函数初始值列表将实参分别传递给每个直接基类。其中基类的构造顺序与派生列表中基类的出现顺序保持一致,而与派生类构造函数初始值列表中基类的顺序无关。多重继承的派生类的拷贝与移动操作 与只有一个基类原创 2015-05-04 22:13:12 · 220 阅读 · 0 评论