C++ Primer Plus翻译心得 16章~附录前

101.STL算法:不同容器,比如vector和list间,如果其内容的值和顺序相同,那么其运用==后值为true。
STL将算法分为了四类:不修改的序列操作;修改的序列操作;排序相关操作;泛化的数值操作。前三种在algorithm头文件中,最后一种在numeric头文件中。
不修改的序列操作,对一定范围内的元素执行操作,操作不会改变容器。for_each()就属于这类。
修改的序列操作,也对一定范围内的元素执行操作,但能改变容器(元素的值或顺序)。
排序相关操作,比如sort()。
泛化的数值操作,操作数值,主要用于vector。
算法可以按照需不需要额外空间分为三类。sort是原地的,copy是拷贝性的,transform则二者都可。一些函数可以原地也可以拷贝,STL的习惯是将拷贝的版本加上_copy,拷贝的形式需要一个迭代器参数来指明结果放哪儿,比如replace函数的原型如下:
template<class ForwardIterator, class T>
void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value);
而它的拷贝版本,原型如下:
template<class InputIterator, class OutputIterator, class T>
OutputIterator replace_copy(InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value);
其返回类型为输出迭代器。一般_copy版本都会返回一个输出迭代器,指向最后一个拷贝的值的地方。
还有一些函数有_if版本。比如replace的if版本:
template<class ForwardIterator, class Predicate class T>
void replace_if(ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value);
如果将范围内的某一个元素应用于Predicate后返回true,则会被替换。
replace也有replace_copy_if()版本。

102.string虽然不属于STL,却在设计上有STL的风格,比如它有begin(), end(), rbegin()和rend()方法,因此也可以用一些STL的接口,比如sort()。string还可以使用next_permutation()算法。

103.除了STL,C++还提供了一些更细化的库,比如complex,提供复数相关的方法。

104.vector,valarray和array:vector是STL中的一种容器,可与其他容器交互;valarray是对数值处理方面特别加强的类模板,不属于STL;array是替代基础类型数组的,提供了begin()等,可使用STL的一些接口。
比如valarray的apply()函数,或者各种重载的操作符,非常有用。其没有begin方法,但C++11提供了一些函数模板,比如sort(begin(vad), end(vad)); // C++11 fix!
尽量不要直接访问valarray中最后一个元素后的地址,可能导致不明行为。而且其有resize()方法来重新确定大小,但不像vector一样可以自动调整大小。valarray还可以使用slice类(valarray头文件中)来代替下标,其构造函数为slice(start,number,stride),比如valarray_example[slice(1,4,3)]=10;即将下标为1,4,7,10的元素赋值为10。slice和gslice可以方便地表示多维数组中的一行、一列等。

105.initializer_list:C++11新增。除非类处理的是大小变化的一组数据,否则不需要特别写一个initializer_list的构造函数。需要的话,使用initializer_list头文件,其提供了begin、end、size方法,比如一个initializer_list对象a,a.begin()等可以访问其中的元素。需要注意,返回的是const迭代器,不能单个修改,但可以将另一个初始化链表赋值给a。

106.为了匹配程序处理速度和硬件读取速度,用缓存区。键盘输入时每次enter后缓存区中的数据才传递给程序。一般地,程序到输入语句后会清空输出缓存。

107.iostream中提供了一些类来管理。streambuf类为缓冲区提供内存,还提供了方法来填满缓冲区、访问缓冲区内容、刷新缓冲区、管理缓冲区内存;ios_base类表示了输入输出流的一些成分,比如开/闭、二进制形式/文本形式;ios类基于ios_base类,其中有一个streambuf对象的指针成员;ostream类从ios衍生,istream类同理;iostream则继承了两者。

108.包含iostream头文件就会自动创建8个流对象(4个给1byte的narrow字符,4个给宽字符):cin和wcin(针对wchar_t);cout与wcout;cerr与wcerr,错误流,一般用于展示错误信息,默认连到标准输出设备如显示器,该流没有缓冲区,也就是说可以直接到屏幕;clog与wclog,与cerr的区别在于其是有缓冲区的。

109.操作系统的重定向:windows命令行下:
counter b
将a文件内容输入程序counter,结果输出到b文件中。
cerr和clog即使在重定向后也会输出到屏幕。一些操作系统允许对cerr和clog重定向,如unix和linux的>2操作。

110.ostream对象认得所有基础类型,并且对<<操作符重载。insertiong操作符还可以用于输入4种指针:const signed char * ,const unsigned char * ,const char * 和void ,因为字符串就是用指针表示的。void 是用来匹配其他类型的指针的。
ostream还提供了put()方法来展示字符,write()方法来展示字符串。put也支持wchar_t,这样用:cout.put(‘W’);,其返回cout的引用,可以连用。write()的原型为basic_ostream<charT,traits>& write(const char_type
s, streamsize n);,如果用cout来调用会导致其用char来特化,并返回cout引用,其在遇到终止符后不会停止;write也可以用于打印数值,但需要转换成char
,此时会将其二进制形式认作ascii等编码并打印。write还可以用于在文件种保存数值。

111.刷新缓冲区:读取时缓冲区很有必要,每次要先填满缓冲区再发送;但输入时最好不要等缓冲区填满,而是再输入前立即刷新(清空)缓冲区。flush可以清空缓冲区,endl也可以而且还会输出一个换行,二者使用方式一样,或者可以使用flush(cout)。

112.cout输出格式:char,若表示可打印字符,默认占一个字符宽度;数值整型默认为10进制,一个字符占一个字符宽度(有负号带-);字符串同样。浮点数的格式与过去有区别:
现在的浮点数默认打印精度为6,若以0结尾则不打印;根据数值,可能以固小数点或科学计数法打印(指数大于等于6或小于等于-5时)。具体习惯上,比如用逗号代替小数点(欧洲习惯),在locale头文件中。
ios_base,ios,ostream的继承关系,ios_base中储存了一些描述格式的信息,并提供了一些方法来改变格式。
dec,hex,oct分别表示10进制,16进制,8进制输出格式,它们是函数,比如hex(cout),然后直到下次指定进制,都会一直以16进制输出。也可写cout<<hex。
width方法可以调整占据的宽度。原型int width()返回当前宽度值,原型int width(int i)则将宽度设为i并返回刚才的宽度值。width方法只会影响下一个输出的东西,然后就会回复为默认值。调整宽度后,默认输出的东西在最右边,前面用空格填充;若宽度小于输出的东西,则会按原样输出。cout.fill(’’);可以设置用填充,这项设置持续有效。
浮点数输出格式:对于固定小数点和科学计数法,精度指小数点右边的数位。cout.precision(2);可设置精度为2,也是持续有效的。ios_base类提供了setf()方法来设置一些格式,比如cout.setf(ios_base::showpoint);可以保证小数点和默认不显示的0一定显示。
setf有两个原型:一是fmtflags setf(fmtflags);,用于设置由一bit控制的一些格式,返回先前的格式,fmtflags 是typedef的bitmask类型(一种可以访问每一bit的类型,可为int、enum或STL的bitset容器)。以下是该原型常用的参数:

C++将8进制和16进制作为无符号处理,所以最后一个参数只对10进制有效(一些编译器可能有效)。
setf的第二个原型为fmtflags setf(fmtflags , fmtflags );,用于由不止一个bit控制的格式。同样也返回先前的格式,第一个参数同上一个原型一样,第二个参数则是一个首先清除某些bit的值,比如设置16进制:cout.setf(ios_base::hex, ios_base::basefield);,先用第二个参数将控制进制的其他bit设置为0,再用第一个参数将控制16进制的bit单独打开。以下为三种第二个参数:

internal指将符号和前缀放在左边,数值放在右边。当使用internal时,精度转而控制总数位。
C++中的浮点格式用F还是E,默认对应C中的%g,fixed对应%f,科学计数法对应%e。

setf改变的可以用unsetf来变回原值,其原型为void unsetf(fmtflags mask);,可以将一个或多个bit设置为默认值0。

较新的C++提供了flag的替代:

iomanip头文件:提供了上面提到的格式设置,但更方便使用,如setprecision()
、setfill()和setw()。

113.cin和cout一样认得各种基础类型,但其参数一般为引用变量。cin可cin>>hex。cin还认得几种指针:signed char * ,char * 和unsigned char *。cin会跳过white space,遇到正确的类型后从输入流中将其提取,遇到非预期类型后停止提取,将其留在输入流中。如果一开始就是非预期类型,则会保持变量值不变并在用于判断时返回0。实际上,cin和cout从ios_base继承了类型iostate(也是bitmask)来表明输入输出的状态,iostate包含了3种ios_base元素:eofbit,badbit和failbit,0为初始值,不同的环境在设置badbit和failbit上有些出入。以下是一些说明:

clear()中的参数bit不会变,其他bit设置为0;而setstate则是仅改变参数bit,其他bit不变,但setstate用clear实现。
eofbit、failbit设置为1时默认不会throw exception,但可通过exceptions方法调整,其返回一个表示3个bit的bitfield,改变流状态一定会用到clear,clear会将当前值与exceptions返回的值比较,如果需要就会throw一个ios_base::failure的例外。比如:cin.exceptions(badbit); // setting badbit causes exception to be thrown
多个设置可以用|:cin.exceptions(badbit | eofbit);
由于历史原因,fail方法在failbit或eofbit为1时都回返回true。

114.get和getline方法:
单个字符输入:
get(char &ch);将读到的字符赋值给ch,不跳过white space,其返回cin的引用,如果遇到EOF则调用setstate(failbit),并不会赋给ch任何值;get(void);则将读到的字符转换为int(或其他整型)并返回,不能连用,遇到EOF会返回值EOF(EOF不用char表示)。get(void)可以用来替换C中的getchar()。

字符串输入:
istream & get(char *, int, char);
istream & get(char *, int);
istream & getline(char *, int, char);
istream & getline(char *, int);
第二个参数需要比待读取的字符个数大1。get将终止符留在流中,getline则将其丢弃。ignore()方法有两个参数,第一个是表明最多读取字符数的int(默认为1),第二个参数是char的终止符(默认为EOF),用于读取到指定个数的字符处或遇到终止符为止,这段字符被丢弃,ignore返回cin的引用。
如果以上方法没有从流中抓取任何一个字符,就会用setstate设置failbit,比如立即遇到EOF,或输入空行(getline输入空行时不会fail,因为它提取了换行并丢弃)。而如果字符达到或超出上限:
如果是getline,比如char temp[30]; while (cin.getline(temp,30)),读了29个字符后,如果遇到EOF,会设置eofbit;如果遇到换行符,会读取并丢弃之;如果是其他字符,就会设置failbit。
如果是get(char *, int);,其先测试字符数目,然后看看是不是到EOF,最后检测是否换行符。超出读取上限时其不会设置failbit,但可以用peek()方法检测下一个字符,若是换行则get(char *, int);读完了一整行,否则get(char *, int);在读完前就停止了。

其他输入流方法:
read(),参数同istream & get(char *, int); ,不同的是末尾不加\0,通常与write()配合用于文件读写。其返回cin引用。
peek()读取下一个字符,但不会从流中提取,用法同ch=cin.get(void)。
gcount()返回上一次非格式提取方法所读取的字符个数,即get、getline、ignore、read等方法,而不能用于>>。
putback()将一个字符放回到输入流,参数为需要放入的字符,返回cin引用。

115.文件输入输出:fstream对象继承了iostream,fin和fout可以使用fail()等方法来检测是否正常,但最好使用is_open(),其还可以检测是否以错误的方式打开文件。
命令行参数,见1120,int main(int argc, char *argv[])。
打开模式的参数(ios_base中):

app模式仅允许在EOF后写入,而ate模式仅仅把读指针放在EOF。
下表给出C中fopen函数的对应:

以二进制读写更快,且数值更精确。比如写一个pl结构体,fout.write( (char *) &pl, sizeof pl);,read同理。但不同的环境,二进制表示可能不同。
对于有虚函数的类,其有一个指向虚函数指针表的指针,将其写入后读取会造成严重后果,可以自己写write和read的方法。同样地,比如string类存储的是指向new字符串的指针,将其读写没有太大意义。
也可以用一个fstream对象处理读写,比如finout.open(file,ios_base::in | ios_base::out | ios_base::binary);,fstram的读、写指针的位置总是相同的。另外,seekg可将写指针移动到参数位置,seekp可将读指针移动到指定位置,seekg原型如下:
basic_istream<charT,traits>& seekg(off_type, ios_base::seekdir);
basic_istream<charT,traits>& seekg(pos_type);
进行char特化,原型等同于:
istream & seekg(streamoff, ios_base::seekdir); //从第二个写指针参数开始算
istream & seekg(streampos);//从文件头开始算
比如fin.seekg(30, ios_base::beg);就是从开始往后30bytes,第二个参数可以有beg、cur和end。
tellg和tellp分别可以获取读、写指针的位置,其都返回一个streampos(从文件头算)来表明位置。
可以用fstream对象读然后修改对象,一般在write后加flush来确保完成修改。

116.需要创建临时文件、需要不重复的文件名,可以用cstdio中的tmpnam函数:
char* tmpnam( char* pszName );,给其一个char*,其会在char*里装一个字符串。L_tmpnam表示字符串最多有几个字符,TMP_MAX则表示最多能创建多少个不重复的文件名,都是cstdio中的常量。创建的名字根据编译器而不同。

117.sstream可提供程序和string对象间的I/O。ostringstream对象提供输出,和ostream格式一样。其输出进入缓冲区(可动态分配空间),然后使用str()方法,返回一个存有缓冲区内容的string对象,然后该ostringstream关闭并且不能再用于写。
要将istringstream对象和一个string对象关联,可以该string对象构造这个istringstream对象。(istringstream对象能否重复使用?有没有open方法?)

最后一章(涉及C++11的新特性和一些boost开源库)
118.移动语义:涉及大量数据的拷贝,可以不需频繁删除,而是更改数据的“所有权”,就像同一盘符更改文件位置一样。这就需要右值引用,一般的构造函数用左值引用,而move constructor用右值引用,移动语义中右值不能是const(通常会将右值在交出所有权,即直接赋值后清零)。除了构造函数,赋值操作符也要使用移动语义。
在一些情况下,可能想使左值当右值使用。这时可以用static_cast<>来转换,或者用std::move()函数(utility头文件)。

119.C++11新增移动构造函数和移动赋值,在原来默认构造、拷贝构造、赋值操作符、析构函数的基础上,但有时定义了其中一个会导致不提供其他几个的默认版本,classname()=default;使用默认构造函数。或者不想让对象有拷贝操作,可以…=delete;。或者对其他成员函数也可以delete,比如一个成员函数使用double为参数,当参数为int时也可以调用,但如果delete掉int版本,那么同样的操作就会编译错误。实际上,delete后成员函数依然存在,只是不能调用了。

120.C++11提供了override关键词,加在函数签名后面。当基类中的虚函数签名与衍生类中对应函数签名不同时,基类的虚函数会被隐藏(无法调用),用override后,如果虚函数没有被override,就会编译时报错。相反,加final关键词则会阻止衍生类重载虚函数。这两个实际上不是关键词,可以用作标识符,仅当出现在特定位置时才有类似关键词的作用。

121.lambda表达式/lambda函数:
generate(起迭代器,止迭代器,数据生成的函数对象)
和函数指针,functor功能一样。lambda表达式可以生成无名函数,可自动推断返回类型,或者可用尾部返回类型来指定:[](double x)->double{int y = x; return x – y;}

122.functional头文件中的function(wrapper),优化相关,减少相同函数签名的模板实例化个数。

123.Variadic template,模板的参数包:接受个数不确定的参数和类型参数。用左边的 …来打包,用右边的…来解包,解包涉及递归。1197

多线程:参见其他书籍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值