Author Archive

C++ Primer Chapter9

星期日, 25 4 月, 2010

1、容器的容器vector< vector<string> > lines;必须用空格隔开两个相邻的>符号,以示这是两个分开的符号,否则,系统会认为>>是单个符号,为右移操作符,并结果导致编译时错误。

2、使用迭代器编写程序时,必须留意哪些操作会使迭代器失效。使用无效迭代器将会导致严重的运行时错误。

3、容器定义的类型别名:

size_type 无符号整型,足以存储此容器类型的最大可能容器长度

iterator 此容器类型的迭代器

const_iterator 元素的只读迭代器类型

reverse_iterator 按逆序寻址元素的迭代器

const_reverse_iterator 元素的只读(不能写)逆序迭代器

difference_type 足够存储两个迭代器差值的有符号整型,可为负数

value_type 元素类型

reference 元素的左值类型,是value_type&的同义词

const_referenct 元素的常量左值类型,等效于const value_type&

4、在顺序容器中添加元素:

push_back

push_front 只适用于list和deque容器类型

insert

5、访问元素:

c.back()

c.front()

c[n] 只适用于vector和deque容器

c.at(n) 只适用于vector和deque容器

6、删除元素:

erase

clear

pop_back

pop_front 只适用于list或deque容器

7、顺序容器的赋值操作:

c1 = c2 删除容器c1的所有元素,然后将c2的元素复制给c1。c1和c2的类型(包括容器类型和元素类型)必须相同

c1.swap(c2) 交换内容:调用完该函数后,c1中存放的是c2原来的元素,c2中存放的则是c1原来的元素。c1和c2的类型必须相同。该函数的执行速度通常要比将c2的元素复制到c1的操作快

c.assign(b, e) 重新设置c的元素:将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器。

c.assign(n, t) 将容器c重新设置为存储n个值为t的元素

如果在不同(或相同)类型的容器内,元素类型不相同但是相互兼容,则其赋值运算必须使用assign函数。例如,可通过assign操作实现将vector容器中一段char*类型的元素赋给string类型的list容器。

由于assign操作首先删除容器中原来存储的所有元素,因此,传递给assign函数的迭代器不能指向调用该函数的容器内元素。

8、vector类提供了两个成员函数:capacity和reserve,使程序员可与vector容器内存分贝的实现部分交互工作。capacity操作获取容器需要分配更多的存储空间之前能够存储的元素总数,而reserve操作则告诉vector容器应该预留多少个元素的存储空间。

9、本质上,适配器是使一事物的行为类似于另一事物的行为的一种机制。容器适配器让一种已存在的容器类型采用另一种不同的抽象类型的工作方式实现。例如,stack(栈)适配器可使任何一种顺序容器以栈的方式工作。

默认的stack和queue都基于deque容器实现,而priority_queue则在vector容器上实现。在创建适配器时,通过将一个顺序容器指定为适配器的第二个类型实参,可覆盖其关联的基础容器类型:

stack< string, vector<string> > str_stk;    // 使stack基于vector实现

对于给定的适配器,其关联的容器必须满足一定的约束条件。stack适配器所关联的基础容器可以是任意一种顺序容器类型。因此,stack栈可以建立在vector、list或者deque容器之上。而queue适配器要求其关联的基础容器必须提供push_front运算,因此只能建立在list或者deque容器上,而不能建立在vector容器上。priority_queue适配器要求提供随机访问功能,因此可建立在vector或deque容器上,但不能建立在list容器上。

10、所有适配器都定义了两个构造函数:默认构造函数用于创建空对象,而带一个容器参数的构造函数将参数容器的副本作为其基础值。例如,架设deq是deque<int>类型的容器,则可用deq初始化一个新的栈,如下所示:

stack<int> stk(deq);

ISoftStone

星期六, 24 4 月, 2010

http://pcedu.pconline.com.cn/empolder/gj/c/0508/687141.html
C/C++ struct的区别
C++ struct全面兼容C struct,且具有“class”的功能。

C++ struct class的区别
成员变量和函数的默认访问权限:struct为public;class为private。
struct可以在定义的时候直接以{}对其成员变量赋初值,而class不能。

SendMessage和PostMessage的区别
SendMessage等到消息被处理后才返回(同步)
PostMessage执行后立即返回(异步)

线程同步
用户模式下的线程同步:
原子访问:Interlocked系列函数
关键段
Slim读/写锁
条件变量

用内核对象进行线程同步
等待函数 事件内核对象
信号量内核对象
互斥量内核对象

ListView和ListControl的区别
CListView从CCtrlView<—CView<—CWnd派生的视图类。
CListCtrl从CWnd派生的控件类。
ListView中包含一个ListControl。
http://baike.baidu.com/view/1980957.htm?fr=ala0_1

C++ Primer Chapter8

星期五, 23 4 月, 2010

1、IO对象不可复制或赋值:只有支持复制的元素类型可以存储在vector或其他容器类型里;形参或返回类型也不能为流类型。如果需要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用。

2、IO标准库的条件状态

strm::iostate 机器相关的整形名,由各个iostream类定义,用于定义条件状态

strm::badbit strm::iostate类型的值,用于指出被破坏的流

strm::failbit strm::iostate类型的值,用于指出失败的IO操作

strm::eofbit strm::iostate类型的值,用于指出流已经到达文件结束符

s.eof() 如果设置了流s的eofbit值,则该函数返回true

s.fail() 如果设置了流s的failbit值,则该函数返回true

s.bad() 如果设置了流s的badbit值,则该函数返回true

s.good() 如果流s处于有效状态,则该函数返回true

s.clear() 将流s中的所有状态值都重设为有效状态

s.clear(flag) 将流s中的某个指定条件状态设置为有效。flag的类型是strm::iostate

s.setstate(flag) 给流s添加指定条件。flag的类型是strm::iostate

s.rdstate() 返回流s的当前条件,返回值类型为strm::iostate

badbit标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了。如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置failbit标志,这种导致设置failbit的问题通常是可以修正的。eofbit是在遇到文件结束符时设置的,此时同时还设置了failbit。

3、下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:

(1)程序正常结束。作为main返回工作的一部分,将清空所有输出缓冲区。

(2)在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。

(3)用操纵符显示地刷新缓冲区,例如行结束符endl。

(4)在每次输出操作执行完后,用unitbuf操纵符设置流的内部状态,从而清空缓冲区。

(5)可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。

4、除了endl操纵符,C++语言还提供了另外两个类似的操纵符。第一个是经常使用的flush,用于刷新流,但不在输出中添加任何字符。第二个则是比较少用的ends,这个操纵符在缓冲区中插入空字符null,然后刷新它:

cout << “hi!” << flush;

cout << “hi!” << ends;

cout << “hi!” << endl;

如果需要刷新所有输出,最好使用unitbuf操纵符。这个操纵符在每次执行完写操作后都刷新流:

cout << unitbuf << “first” << “second” << nounitbuf;

等价于:

cout << “first” << “second” << flush;

nounitbuf操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式。

5、tie函数可用istream或ostream对象调用,使用一个指向ostream对象的指针形参。调用tie函数时,将实参流绑在调用该函数的对象上。如果一个流调用tie函数将其本身绑在传递给tie的ostream实参对象上,则该流上的任何IO操作都会刷新实参所关联的缓冲区。一个ostream对象每次只能与一个istream对象绑在一起。如果在调用tie函数时传递实参0,则打破该流上已存在的捆绑。

6、由于历史原因,IO标准库使用C风格字符串而不是C++ string类型的字符串作为文件名。在创建fstream对象时,如果调用open或使用文件名作初始化式,需要传递的实参应为C风格字符串,而不是标准库string对象。程序常常从标准输入获得文件名。通常,比较好的方法是将文件名读入string对象,而不是C风格字符数组。假设要使用的文件名保存在string对象中,则可调用c_str成员获取C风格字符串。

7、如果程序员需要重用文件流读写多个文件,必须在读另一个文件之前调用close关闭前一个文件,并调用clear清除该流的状态。

8、文件模式

in 打开文件做读操作

out 打开文件做写操作

app 在每次写之前找到文件尾

ate 打开文件后立即将文件定位在文件尾

trunc 打开文件时清空已存在的文件流

binary 以二进制模式进行IO操作

9、stringsteam提供转换和/或格式化

C++ Primer Chapter7

星期五, 23 4 月, 2010

1、函数由函数名以及一组操作数类型唯一地表示。C++使用调用操作符(即一对圆括号)实现函数的调用。正如其他操作符一样,调用操作符需要操作数并产生一个结果。调用操作符的操作数是函数名和一组(有可能是空的)由逗号分隔的实参。

2、形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值,如果形参为引用类型,则它只是实参的别名。

函数的形参可以是指针,此时将复制实参指针。与其他非引用类型的形参一样,该类形参的任何改变也仅作用于局部副本(形参复制实参的值)。如果函数将新指针赋值给形参,主调函数使用的实参指针的值没有改变。事实上被复制的指针只影响对指针所指对象的赋值,即如果函数形参是非const类型的指针,则函数可通过指针实现赋值,修改指针所指向对象的值。

可以将指向const对象的指针初始化为指向非const对象,但不可以让指向非const对象的指针指向const对象。

在调用函数时,如果该函数使用非引用的非const形参,则既可给该函数传递const实参也可传递非const的实参。因为初始化复制了初始化式的值,所以可以用const对象初始化非const对象,反之亦然。

3、从C语言背景转到C++的程序员习惯通过传递指针来实现对实参的访问。在C++中,使用引用形参则更安全和自然。

如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为const引用。

非const引用形参只能与完全同类型的非const对象关联。应该将不修改相应实参的形参定义为const引用。如果将这样的形参定义为非const引用,则毫无必要的限制了该函数的使用。如:

int incr(int &val);

short v1 = 0;

int v2 = incr(v1);    // int &只能绑定int对象

应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活。这样的形参既不能用const对象初始化,也不能用字面值(常量)或产生右值的表达式实参(临时变量)初始化。

4、使用数组形参或指针形参传递数组,编译器只会检查实参是不是指针、指针的类型和数组元素的类型是否匹配,而不会检查数组的长度。如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型的一部分。编译器检查数组实参的大小与形参的大小是否匹配。

&arr两边的圆括号是必需的,因为下标操作符具有更高的优先级:

f(int &arr[10])    // error: arr is an array of references

f(int (&arr)[10])    // ok: arr is a reference to an array of 10 ints

5、C++中的省略符形参是为了编译使用了varargs的C语言程序。关于如何使用varargs,请查阅所用C语言编译器的文档。对于C++程序,只能将简单数据类型传递给含有省略符形参的函数。实际上,当需要传递给省略符形参时,大多数类类型对象都不能正确地复制。

6、为了主函数main的返回值独立于机器,cstdlib头文件定义了两个预处理变量,分别表示程序运行成功和失败:

#include <cstdlib>

int main()

{

    if(some_failure)

        return EXIT_FAILURE;

    else

        return EXIT_SUCCESS;

}

7、当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。理解返回引用至关重要的是:千万不能返回局部变量的引用。

返回引用的函数返回一个左值(变量的别名,可以赋值)。

8、默认实参是通过给形参表中的形参提供明确的初始值来指定的。程序员可为一个或多个形参定义默认值。但是,如果有一个形参具有默认实参,那么,它后面所有的形参都必须有默认实参。

9、只有当定义它的函数被调用时才存在的对象称为自动对象。static局部对象一旦被创建,在程序结束前都不会被撤销。

10、内联函数应该在头文件中定义,这一点不同于其他函数。

编译器隐式地将在类内定义的成员函数当作内联函数。

内联说明对于编译器来说只是一个建议,编译器可以选择忽略这个建议。

11、每个成员函数都有一个额外的、隐含的形参this。

const改变了隐含的this形参的类型(Object *const this变成了const Object *const this)。用这种方式使用const的函数称为常量成员函数。由于this是指向const对象的指针,const成员函数不能修改调用该函数的对象。

const对象、指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用它们来调用非const成员函数,则是错误的。

12、在冒号和花括号之间的代码成为构造函数的初始化列表。除非在初始化列表中有其他表述,否则具有类类型的成员皆被其默认构造函数自动初始化。

Object: iMin(0), iMax(100) {}    // Object构造函数

13、由编译器创建的默认构造函数通常成为合成的默认构造函数,它将依据如同变量初始化的规则初始化类中所有成员。对于具有类类型的成员,则会调用该成员所属类自身的默认构造函数实现初始化。内置类型成员的初值依赖于对象如何定义。如果对象在全局作用域中定义(即不在任何函数中)或定义为静态局部对象,则这些成员将被初始化为0。如果对象在局部作用域中定义,则这些成员没有初始化。除了给它们赋值之外,处于其他任何目的对未初始化成员的使用都没有定义。

14、允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数。具有函数类型的形参所对应的实参将被自动转换为指向相应函数类型的指针。

C++ Primer Chapter6

星期二, 20 4 月, 2010

1、switch表达式必须产生一个整数结果,case标号必须是整型常量表达式。如果两个case标号具有相同的值,同样也会导致编译时的错误。

case 3.14:    // 不是整型

case iVal:    // 不是常量

2、对于switch结构,只能在它的最后一个case标号或default标号后面定义变量。制定这个规则是为了避免出现代码跳过变量的定义和初始化的情况。

3、在循环条件中定义的变量在每次循环里都要经历创建和撤销的过程。

4、可以在for语句的init-statement中定义多个对象;但是不管怎么样,该处只能出现一个语句,因此所有的对象必须具有相同的一般类型。

5、goto语句不能跨越变量的定义语句向前跳转;如果确实需要在goto和其跳转对应的标号之间定义变量,则定义必须放在一个块语句中。

6、与其他块语句一样,try块引入局部作用域,在try块中声明的变量,包括catch子句中声明的变量,不能在try外面引用。

7、可使用NDEBUG预处理变量实现有条件的调试代码:

#ifndef NDEBUG

// Error

#endif

8、预处理器还定义了其余四种在调试时非常有用的常量:

__FILE__    // 文件名

__LINE__    // 当前行号

__DATE__    // 文件被编译的日期

__TIME__    // 文件被编译的时间

9、与异常不同(异常用于处理程序执行时预期要发生的错误),程序员使用assert来测试“不可能发生”的条件。