工作到了今天,看到了很多,也想到了很多,其实感觉自己一路走来还是不容易。刚工作的时候的心态还是很稚嫩,其实一直到今天自己还是在不停地摸索,怎么去完善自己的情商。其实我一直觉得,知识,尤其是工作上的知识,要掌握下来是不难的。我觉得更难得是怎么去让自己的思考方式比别人更加好,这更是一条更难跨越的沟壑。无论什么知识,其实你能掌握的,别人比你花个多两倍,三倍的时间,总也能掌握到得,但是一个人比别人的“能力”显得更强,更多的是这个人在一个领域,一个问题上是否能思考得更加深入,能够更多地从多个方面去切入问题的核心来思考。
到了今时今日,我当然深知自己的知识体系还是有很大的不足,相对于很多ACM牛人,我的解题能力不足,相对于在此领域探索很多年的人,我的经验,我的思考方式还是有很大的不足。怎么能够从各个方面发挥自己的能力,能更好地进步呢?这应该是成为我以后几年一直思考的问题。
回想自己的职业之路,只工作了一年便跳槽显然并不是最好的选择,另外跳的对象也并不是一个很好的平台。虽然自己一直认为自己一定会走上创业这条路,但是现在自己却越来越觉得还是更喜欢和技术打交道,还是希望自己能在一个很好的平台上去做自己喜欢的事情,现在,显然我还没找到这样一个平台。
2009年5月1日星期五
InnoDB和MyISAM的差别[zz]
InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
MyIASM是IASM表的新版本,有如下扩展:
二进制层次的可移植性。
NULL列索引。
对变长行比ISAM表有更少的碎片。
支持大文件。
更好的索引压缩。
更好的键码统计分布。
更好和更快的auto_increment处理。
以下是一些细节和具体实现的差别:
1.InnoDB不支持FULLTEXT类型的索引。
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”
任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。
MyIASM是IASM表的新版本,有如下扩展:
二进制层次的可移植性。
NULL列索引。
对变长行比ISAM表有更少的碎片。
支持大文件。
更好的索引压缩。
更好的键码统计分布。
更好和更快的auto_increment处理。
以下是一些细节和具体实现的差别:
1.InnoDB不支持FULLTEXT类型的索引。
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”
任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。
2009年2月18日星期三
[zt]C++中的typename关键字(想哪儿说哪儿)
可能是C++的设计者(BJ?)觉得没用必要引入更多的关键字,其实模板刚刚引入C++中的时候并没有typename关键字。那时候定义类模板的类型参数通常使用class关键字。如:
template
class Test
{
public :
T t;
.....
};
随着模板应用的推广,大家发现使用typedef非常关键,因为实例化后的模板定义通常很长,通过使用typedef可以有效的缩短代码长度。如:
class UseTest
{
public:
typedef Test intTT;
...
};
这时问题就来了,当我写UseTest::intTT,这个intTT究竟是UseTest的一个静态成员(static)还是一个类型呢?所以typename关键字就引入了C++。
所以在定义一个intTT的对象时,我们就要这样写:
typename UseTest::intTT int_tt_obj;
通过typename明确指出intTT是一个类型而不是一个静态成员。
C++中的typename关键字(想哪儿说哪儿)
template
class Test
{
public :
T t;
.....
};
随着模板应用的推广,大家发现使用typedef非常关键,因为实例化后的模板定义通常很长,通过使用typedef可以有效的缩短代码长度。如:
class UseTest
{
public:
typedef Test
...
};
这时问题就来了,当我写UseTest::intTT,这个intTT究竟是UseTest的一个静态成员(static)还是一个类型呢?所以typename关键字就引入了C++。
所以在定义一个intTT的对象时,我们就要这样写:
typename UseTest::intTT int_tt_obj;
通过typename明确指出intTT是一个类型而不是一个静态成员。
C++中的typename关键字(想哪儿说哪儿)
2009年1月19日星期一
python Unicode I/O
在系统内部, Unicode 字符串被表示为一个16位整数序列,8-bit 字符串则是一个字节序列, 绝大多数字符串操作被扩展为能够处理更宽范围的字符值。只要 Unicode 字符串被转换为字节流,就必然会产生一系列问题(需要解决)。首先,要考虑现有软件的兼容性, 对那些仅支持 ASCII或其它 8-bit的软件来说,将 Unicode字符串转化为 ASCII字符串是较好的方法。其次, 16-bit 字符占用两个字节,字节顺序问题虽然比较无聊但必须考虑。对一个Unicode字符 U+HHLL 来说, 小端法编码方案将低位字节放在前面, 即 LL HH;大端法编码方案则将高位字节放在前面,即 HH LL. 就因为这么点问题, 不指定编码方案,你就无法将原始 Unicode 数据写入文件.
要解决这些问题, 只能根据特定的编码规则将 Unicode 字符串进行客观表示。这些规则定义了如何将 Unicode 字符表示为字节序列。在第四章, 针对 unicode()及 s.encode() 首先介绍了编码规则。举例来说:
Toggle line numbersToggle line numbers
1 a = u"M\u00fcller"
2 b = "Hello World"
3 c = a.encode('utf-8') # Convert a to a UTF-8 string
4 d = unicode(b) # Convert b to a Unicode string
codecs 模块用类似的技术解决了 Unicode 的输入输出问题。 codecs 模块拥有一系列转换函数依据不同的编码方案完成字节数据和 Unicode 字符串的转换。通过调用 codecs.lookup(encoding) 函数来选择一种编码方案。这个函数返回一个包括四个元素的 tuple (enc_func, decode_func, stream_reader, stream_writer ). 举例来说:
Toggle line numbersToggle line numbers
1 import codecs
2 (utf8_encode, utf8_decode, utf8_reader, utf8_writer) = \
3 codecs.lookup('utf-8')
enc_func (u [,errors ]) 函数接受一个 Unicode 字符串 u ,返回值是tuple(s , len).其中 s 是转码后的 8-bit 字符串(内容为 u 的一部分或全部), len 是被成功转换的 Unicode 字符数. decode_func(s [,errors]) 函数接受一个 8-bit 字符串,返回值是 tuple(u, len)。其中 u 是一个 Unicode字符串(内容为 s 的一部分或全部),len 是被成功转换的字符数。errors 决定转化过程中的错误如何处理,它的值可能是 'strict' 或 'ignore' 或 'replace'。若是 'strict'模式, 编码错误将引发 UnicodeError 异常。 若是 'ignore' 模式, 编码错误将被忽略。若是 'replace' 模式,无法转换的编码将被替换为 '?' 字符(Unicode字符U+FFFD或8-bit字符 '?')。
stream_reader 用来对文件对象进行封装,以支持 Unicode 数据读取. 调用 stream_reader (file) 返回封装后的文件对象,它的 read(), readline(), 及 readlines() 方法支持读取 Unicode 字符串数据. stream_writer 用来对文件对象进行封装,以支持将 Unicode 字符串写入文件。调用 stream_writer(file) 返回封装后的文件对象,它的 write() 和 writelines() 方法将 Unicode 字符串按给定的编码转换为字节流写入文件中。
下面的例子演示了如何使用这些方法处理 UTF-8 编码的 Unicode 数据:
Toggle line numbersToggle line numbers
1 # 输出 Unicode 数据到文件
2 ustr = u'M\u00fcller' # 一个Unicode 字符串
3
4 outf = utf8_writer(open('foo','w')) # 创建 UTF-8 字节流
5 outf.write(ustr)
6 outf.close()
7
8 # 从一个文件读取 unicode 数据
9 infile = utf8_reader(open('bar'))
10 ustr = infile.read()
11 infile.close()
当处理 Unicode文件时, 数据编码通常内嵌在文件本身当中。举例来说,XML 解析器根据文件的前几个字节'' 来判断文件编码. 如果最初的四个值是 3C 3F 78 6D ('
用类似下面的代码来读取文档的编码:
Toggle line numbersToggle line numbers
1 f = open("somefile")
2 # Determine encoding
3 ...
4 (encoder,decoder,reader,writer) = codecs.lookup(encoding)
5 f = reader(f) # Wrap file with Unicode reader
6 data = f.read() # Read Unicode data
7 f.close()
1.6.1. Unicode 数据编码
表 9.2 列出了codecs模块中目前正在使用的所有编码
表 9.2. codecs 模块中的全部编码器
编码 描述
'ascii' ASCII 编码
'latin-1', 'iso-8859-1' Latin-1 或 ISO-8859-1 编码
'utf-8' 8-bit 变长编码
'utf-16' 16-bit 变长编码
'utf-16-le' UTF-16, 显式小端编码方案
'utf-16-be' UTF-16, 显式大端编码方案
'unicode-escape' 和 u"string " 格式相同
'raw-unicode-escape' 和 ur"string "格式相同
下面的段落描述了各种编码的细节:
'ascii' 编码:
'ascii' 编码, 字符值的范围被限制在[0,0x7f] 和 [U+0000, U+007F]。超出这个范围的任何字符都是非法的。
'iso-8859-1' 或 'latin-1' 编码:
字符可以是任意的 8-bit 值([0,0xff] 及 [U+0000, U+00FF]). 取值范围 [0,0x7f] 内的字符对应 ASCII 字符集,取值范围 [0x80,0xff] 内的字符对应 ISO-8859-1 或 扩展 ASCII 字符集。超出 [0,0xff] 取值范围的任何字符都会造成错误。
'utf-8' 编码:
UTF-8 是一种变长编码,它能表示所有的Unicode字符。一个单独的字节用来表示值为 0–127 的 ASCII 字符。所有其它字符均被表示为多字节序列(双字节或3字节)。这些字节的编码见下表
Unicode 字符 Byte 0 Byte 1 Byte 2
U+0000 - U+007F 0nnnnnnn
U+007F - U+07FF 110nnnnn 10nnnnnn
U+0800 - U+FFFF 1110nnnn 10nnnnnn 10nnnnnn
对两字节序列, 第一个字节的前三个比特总是 110. 对三字节序列, 第一个字节的前三个比特总是 1110. 多字节序列的所有后来字节的前两个比特都是 10。
UTF-8 格式一个字符最多可以使用六个字节。 Python 中, 四字节 UTF-8 序列被称为代理对,用来对一对 Unicode 字符进行编码。这一对字符的取值都在[U+D800, U+DFFF]范围内并组合成一个 20-bit 的值. 代理对这样编码:四字节序列 111100nn 10nnnnnn 10nnmmmm 10mmmmmm 被编码成这样一对: U+D800 + N , U+DC00 + M , 其中 N 是高10位, M 是低十位。五字节和六字节 UTF-8 序列(开始位分别为 111110 和 1111110) 用来对32比特值的Unicode字符进行编码。Python目前不支持五字节和六字节UTF-8序列。如果数据流中存在这样的数据会引发 UnicodeError 异常。
UTF-8 编码对旧程序支持的相当好. 首先,标准 ASCII 字符的编码没有发生任何改变。这意味着 UTF-8 编码的 ASCII 字符串与传统的 ASCII 字符串完全相同。其次, UTF-8 编码的多字节序列未内嵌 null 字节。这样现有的基于 C 库的软件和程序所使用的 null-结尾的 8-bit 字符串可以与 UTF-8 字符串相容. 最后,UTF-8 编码 保留了字符串的字典顺序。也就是说如果 a 和 b 是 Unicode 字符串并且 a < b, 则当 a 和 b被转化为UTF-8编码后, a < b 仍然成立。因此,写给 ASCII 字符串的排序算法及其它与顺序有关的算法也一样可以工作在 UTF-8 编码上。
'utf-16' , 'utf-16-be' , and 'utf-16-le' 编码:
UTF-16 是一种变长16位编码,其中 Unicode 被记录为 16-bit 值。如果未指定字节顺序,则默认为大端法编码方案。另外,一个特殊的字符 U+FEFF 可以用来显式的标记UTF-16 数据流的字节顺序。.大端编码方案, U+FEFF 字符表示 zero-width nonbreaking space, 而 U+FFFE 则是一个非法的 Unicode字符。因此,编码器可以使用这个字节顺序 FE FF 或 FF FE 来判断字节顺序。当读取 Unicode 数据时,Python会自动移去这个标志。
'utf-16-be' 编码 显式指定届UTF-16 大端编码(big endian), 'utf-16-le' 显式指定 UTF-16 小端编码(little ending)。
尽管已经有多种 UTF-16 的扩展以支持更多字符,目前的 Python 并不支持任何这样的扩展。
'unicode-escape' 及 'raw-unicode-escape' 编码:
这些编码方法被用来转换 Unicode 字符串到 Python使用的 Unicode 字符串及原始Unicode字符串。举例来说:
Toggle line numbersToggle line numbers
1 s = u'\u14a8\u0345\u2a34'
2 t = s.encode('unicode-escape') #t = '\u14a8\u0345\u2a34'
1.6.2. Unicode 字符属性
除了实现输入输出之外, 使用 Unicode 的程序必然会有测试 Unicode 字符属性的需要(是否大小写、是否数字、是否空白等等)。 unicodedata 模块提供了这些 unicode字符数据库。. 常规字符属性可以通过 unicodedata.category(c) 函数得到. 例如, unicodedata.category(u"A") 返回 'Lu', 表示这个字符是一个大写字符。更多关于Unicode 字符数据库及 unicodedata 模块的细节,请参阅附录A。
要解决这些问题, 只能根据特定的编码规则将 Unicode 字符串进行客观表示。这些规则定义了如何将 Unicode 字符表示为字节序列。在第四章, 针对 unicode()及 s.encode() 首先介绍了编码规则。举例来说:
Toggle line numbersToggle line numbers
1 a = u"M\u00fcller"
2 b = "Hello World"
3 c = a.encode('utf-8') # Convert a to a UTF-8 string
4 d = unicode(b) # Convert b to a Unicode string
codecs 模块用类似的技术解决了 Unicode 的输入输出问题。 codecs 模块拥有一系列转换函数依据不同的编码方案完成字节数据和 Unicode 字符串的转换。通过调用 codecs.lookup(encoding) 函数来选择一种编码方案。这个函数返回一个包括四个元素的 tuple (enc_func, decode_func, stream_reader, stream_writer ). 举例来说:
Toggle line numbersToggle line numbers
1 import codecs
2 (utf8_encode, utf8_decode, utf8_reader, utf8_writer) = \
3 codecs.lookup('utf-8')
enc_func (u [,errors ]) 函数接受一个 Unicode 字符串 u ,返回值是tuple(s , len).其中 s 是转码后的 8-bit 字符串(内容为 u 的一部分或全部), len 是被成功转换的 Unicode 字符数. decode_func(s [,errors]) 函数接受一个 8-bit 字符串,返回值是 tuple(u, len)。其中 u 是一个 Unicode字符串(内容为 s 的一部分或全部),len 是被成功转换的字符数。errors 决定转化过程中的错误如何处理,它的值可能是 'strict' 或 'ignore' 或 'replace'。若是 'strict'模式, 编码错误将引发 UnicodeError 异常。 若是 'ignore' 模式, 编码错误将被忽略。若是 'replace' 模式,无法转换的编码将被替换为 '?' 字符(Unicode字符U+FFFD或8-bit字符 '?')。
stream_reader 用来对文件对象进行封装,以支持 Unicode 数据读取. 调用 stream_reader (file) 返回封装后的文件对象,它的 read(), readline(), 及 readlines() 方法支持读取 Unicode 字符串数据. stream_writer 用来对文件对象进行封装,以支持将 Unicode 字符串写入文件。调用 stream_writer(file) 返回封装后的文件对象,它的 write() 和 writelines() 方法将 Unicode 字符串按给定的编码转换为字节流写入文件中。
下面的例子演示了如何使用这些方法处理 UTF-8 编码的 Unicode 数据:
Toggle line numbersToggle line numbers
1 # 输出 Unicode 数据到文件
2 ustr = u'M\u00fcller' # 一个Unicode 字符串
3
4 outf = utf8_writer(open('foo','w')) # 创建 UTF-8 字节流
5 outf.write(ustr)
6 outf.close()
7
8 # 从一个文件读取 unicode 数据
9 infile = utf8_reader(open('bar'))
10 ustr = infile.read()
11 infile.close()
当处理 Unicode文件时, 数据编码通常内嵌在文件本身当中。举例来说,XML 解析器根据文件的前几个字节'' 来判断文件编码. 如果最初的四个值是 3C 3F 78 6D ('
用类似下面的代码来读取文档的编码:
Toggle line numbersToggle line numbers
1 f = open("somefile")
2 # Determine encoding
3 ...
4 (encoder,decoder,reader,writer) = codecs.lookup(encoding)
5 f = reader(f) # Wrap file with Unicode reader
6 data = f.read() # Read Unicode data
7 f.close()
1.6.1. Unicode 数据编码
表 9.2 列出了codecs模块中目前正在使用的所有编码
表 9.2. codecs 模块中的全部编码器
编码 描述
'ascii' ASCII 编码
'latin-1', 'iso-8859-1' Latin-1 或 ISO-8859-1 编码
'utf-8' 8-bit 变长编码
'utf-16' 16-bit 变长编码
'utf-16-le' UTF-16, 显式小端编码方案
'utf-16-be' UTF-16, 显式大端编码方案
'unicode-escape' 和 u"string " 格式相同
'raw-unicode-escape' 和 ur"string "格式相同
下面的段落描述了各种编码的细节:
'ascii' 编码:
'ascii' 编码, 字符值的范围被限制在[0,0x7f] 和 [U+0000, U+007F]。超出这个范围的任何字符都是非法的。
'iso-8859-1' 或 'latin-1' 编码:
字符可以是任意的 8-bit 值([0,0xff] 及 [U+0000, U+00FF]). 取值范围 [0,0x7f] 内的字符对应 ASCII 字符集,取值范围 [0x80,0xff] 内的字符对应 ISO-8859-1 或 扩展 ASCII 字符集。超出 [0,0xff] 取值范围的任何字符都会造成错误。
'utf-8' 编码:
UTF-8 是一种变长编码,它能表示所有的Unicode字符。一个单独的字节用来表示值为 0–127 的 ASCII 字符。所有其它字符均被表示为多字节序列(双字节或3字节)。这些字节的编码见下表
Unicode 字符 Byte 0 Byte 1 Byte 2
U+0000 - U+007F 0nnnnnnn
U+007F - U+07FF 110nnnnn 10nnnnnn
U+0800 - U+FFFF 1110nnnn 10nnnnnn 10nnnnnn
对两字节序列, 第一个字节的前三个比特总是 110. 对三字节序列, 第一个字节的前三个比特总是 1110. 多字节序列的所有后来字节的前两个比特都是 10。
UTF-8 格式一个字符最多可以使用六个字节。 Python 中, 四字节 UTF-8 序列被称为代理对,用来对一对 Unicode 字符进行编码。这一对字符的取值都在[U+D800, U+DFFF]范围内并组合成一个 20-bit 的值. 代理对这样编码:四字节序列 111100nn 10nnnnnn 10nnmmmm 10mmmmmm 被编码成这样一对: U+D800 + N , U+DC00 + M , 其中 N 是高10位, M 是低十位。五字节和六字节 UTF-8 序列(开始位分别为 111110 和 1111110) 用来对32比特值的Unicode字符进行编码。Python目前不支持五字节和六字节UTF-8序列。如果数据流中存在这样的数据会引发 UnicodeError 异常。
UTF-8 编码对旧程序支持的相当好. 首先,标准 ASCII 字符的编码没有发生任何改变。这意味着 UTF-8 编码的 ASCII 字符串与传统的 ASCII 字符串完全相同。其次, UTF-8 编码的多字节序列未内嵌 null 字节。这样现有的基于 C 库的软件和程序所使用的 null-结尾的 8-bit 字符串可以与 UTF-8 字符串相容. 最后,UTF-8 编码 保留了字符串的字典顺序。也就是说如果 a 和 b 是 Unicode 字符串并且 a < b, 则当 a 和 b被转化为UTF-8编码后, a < b 仍然成立。因此,写给 ASCII 字符串的排序算法及其它与顺序有关的算法也一样可以工作在 UTF-8 编码上。
'utf-16' , 'utf-16-be' , and 'utf-16-le' 编码:
UTF-16 是一种变长16位编码,其中 Unicode 被记录为 16-bit 值。如果未指定字节顺序,则默认为大端法编码方案。另外,一个特殊的字符 U+FEFF 可以用来显式的标记UTF-16 数据流的字节顺序。.大端编码方案, U+FEFF 字符表示 zero-width nonbreaking space, 而 U+FFFE 则是一个非法的 Unicode字符。因此,编码器可以使用这个字节顺序 FE FF 或 FF FE 来判断字节顺序。当读取 Unicode 数据时,Python会自动移去这个标志。
'utf-16-be' 编码 显式指定届UTF-16 大端编码(big endian), 'utf-16-le' 显式指定 UTF-16 小端编码(little ending)。
尽管已经有多种 UTF-16 的扩展以支持更多字符,目前的 Python 并不支持任何这样的扩展。
'unicode-escape' 及 'raw-unicode-escape' 编码:
这些编码方法被用来转换 Unicode 字符串到 Python使用的 Unicode 字符串及原始Unicode字符串。举例来说:
Toggle line numbersToggle line numbers
1 s = u'\u14a8\u0345\u2a34'
2 t = s.encode('unicode-escape') #t = '\u14a8\u0345\u2a34'
1.6.2. Unicode 字符属性
除了实现输入输出之外, 使用 Unicode 的程序必然会有测试 Unicode 字符属性的需要(是否大小写、是否数字、是否空白等等)。 unicodedata 模块提供了这些 unicode字符数据库。. 常规字符属性可以通过 unicodedata.category(c) 函数得到. 例如, unicodedata.category(u"A") 返回 'Lu', 表示这个字符是一个大写字符。更多关于Unicode 字符数据库及 unicodedata 模块的细节,请参阅附录A。
2008年12月24日星期三
2008总结
时间过得真快,一年又快到尽头了,又是一年总结的时候了。今年是我的本命年,原本听说本命年的人的际遇会很极端,要不就是很好,要不就是很差。我也很低调地度过了我生命中的第二个本命年,今年也的确发生了一些蛮大的事情吧。那就顺着说一下,总结一下经验,同时也展望一下明年,希望那个明年做得更好一点。
08年初在原公司第一个独立完成的产品上线,互联网上第一次有了我的作品,小庆贺一下。并且开始打羽毛球,基本每个周末都会去一次,还买了一只100多块的球拍,感觉身体慢慢好了一点,也习惯了这样的生活习惯。接着就是在一次偶然的和一个网友的聊天中被“看上”,接受了另一家公司的电话面试,并且还跑到了广州见了现在的老大一面,并且聊了一些工作上的看法,不过感觉并不太好,而且当时我去广州的目的也并不是面试,而是想尝一次我一直想喝的大加司的奶茶(现在已经不想喝了,听说都是奶精泡的),不过回来后竟然收到了offer,而且待遇给的还不错,于是决定了我生命中的第一次跳槽。
向原公司提出了离职,因为还没满合同期,原本需要交违约金,不过公司做法不太正规,被我搬出劳动仲裁吓到了,于是免了巨额违约金,呵呵。还好,于是还比较顺利地走人了,不过其实还是有点不舍得的,原公司还是一个比较适合做技术的地方,可惜比较吝啬:)还记得搬离深圳的前一天狂风暴雨,而当时住的地方收拾得很乱,一塌糊涂,我们当时窝在屋里点了一个永和大王的牛柳饭,还蛮好吃的:)在广州住的地方离公司当时的地址很近,于是我过了一段很闲适的日子,每天中午都回住的地方吃中午饭,并且打个瞌睡,下午洗把脸再去上班,这是当年上学的时候才有的待遇啊!!!!可惜这种日子不能维持多久,公司就搬到了天河城的写字楼 ,于是每天开始逼地铁,直至今天。
今年比较成功的地方就是实现了工作选择上的一个跳跃,可惜很多东西都是福兮祸所倚,在这里我过得并不算十分开心,也许不太和我自己的性格吧,不过世事往往没有十全十美的,也许这样才能使我有动力去追寻自己的梦想吧。展望2009,最大的希望当然还是事业再上一层楼啦,感情方面,希望继续稳定恩爱,两个人能够磨合得更好,吵架能够再少一点。暂时没什么更具体的想法啦,很多东西要一步步地去走,希望新年更多阳光,少点乌云。
今年比较成功的地方就是实现了工作选择上的一个跳跃,可惜很多东西都是福兮祸所倚,在这里我过得并不算十分开心,也许不太和我自己的性格吧,不过世事往往没有十全十美的,也许这样才能使我有动力去追寻自己的梦想吧。展望2009,最大的希望当然还是事业再上一层楼啦,感情方面,希望继续稳定恩爱,两个人能够磨合得更好,吵架能够再少一点。暂时没什么更具体的想法啦,很多东西要一步步地去走,希望新年更多阳光,少点乌云。
2008年12月8日星期一
dynamic_cast详解
作为四个内部类型转换操作符之一的dynamic_cast和传统的C风格的强制类型转换有着巨大的差别。除了dynamic_cast以外的转换,其行为的都是在编译期就得以确定的,转换是否成功,并不依赖被转换的对象。而dynamic_cast则不然。在这里,不再讨论其他三种转换和C风格的转换。
首先,dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。
先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚方法,也就无法判断一个基类指针变量所指对象的真实类型, 这时候,dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.而这种转换其实并不需要dynamic_cast参与.
也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的.
下面看一个例子:
struct B1{
virtual ~B1(){}
};
struct B2{
virtual ~B2(){}
};
struct D1 : B1, B2{};
int main()
{
D1 d;
B1* pb1 = &d;
B2* pb2 = dynamic_cast(pb1);//L1
B2* pb22 = static_cast(pb1); //L2
return 0;
}
上述定义中可以看到,B1和B2是不相关的类,从L1可以看到,dynamic_cast允许这种转换:只要B1存在多态方法.
L2将编译失败,static_cast并不允许两个完全不相干的类互相转换.
dynamic_cast的这种特性,在提取一个对象的某个接口的时候,非常有用,它很类似于实现了COM的QueryInterface的功能。
正好在网上看到一个讲解强制转型的文章:
http://www.xker.com/article/articleview/2005-8-23/article_view_2732.htm
文中这样描述:
--
dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。
---这个描述是不完整的,dynamic_cast 固然可以实现完全的向下转型,也可以实现更为强大的QueryInterface的功能。
首先,dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。
先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚方法,也就无法判断一个基类指针变量所指对象的真实类型, 这时候,dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.而这种转换其实并不需要dynamic_cast参与.
也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的.
下面看一个例子:
struct B1{
virtual ~B1(){}
};
struct B2{
virtual ~B2(){}
};
struct D1 : B1, B2{};
int main()
{
D1 d;
B1* pb1 = &d;
B2* pb2 = dynamic_cast
B2* pb22 = static_cast
return 0;
}
上述定义中可以看到,B1和B2是不相关的类,从L1可以看到,dynamic_cast允许这种转换:只要B1存在多态方法.
L2将编译失败,static_cast并不允许两个完全不相干的类互相转换.
dynamic_cast的这种特性,在提取一个对象的某个接口的时候,非常有用,它很类似于实现了COM的QueryInterface的功能。
正好在网上看到一个讲解强制转型的文章:
http://www.xker.com/article/articleview/2005-8-23/article_view_2732.htm
文中这样描述:
--
dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。
---这个描述是不完整的,dynamic_cast 固然可以实现完全的向下转型,也可以实现更为强大的QueryInterface的功能。
2008年8月20日星期三
2008年8月18日星期一
关于函数覆盖
前几天接到一个电话,那人是循着我的简历找到本人的。并和他讨论几个技术问题,然后被他一个函数覆盖的问题雷住了,以前根本没碰到过这个名词,等到聊完后,上网搜了搜,发现一篇文章:http://zhidao.baidu.com/question/2196348.html?fr=qrl,但是这篇文章其实也没说到什么很新的东西。其实无论是函数覆盖还是虚函数,都是遵循一个概念:如果不声明虚函数,基类指针是根本不能通过虚函数表访问到继承类的函数的,只有通过虚函数表,才能实现动态连编。有兴趣者可以自己写个小code来看下。
2008年8月5日星期二
刘荻:不锈钢老鼠上网记
我开始上网是在2000年初,起初是在几个大学的BBS混,后来混到了网易社区和其它几个地方。这段时间我只是潜水看贴,从不发言。2000年夏天我接触到了李永刚老师办的“思想的境界”,当时它的论坛设在“西祠胡同”里的“社会与人文”下面,所以我便又混到了西祠,并且发现了那里的“民主论坛”(后改名为“民主和人权”),这就是现在的“民主和自由”论坛的前身。我在西祠上注册了“不锈钢老鼠”这个ID,主要是为了看贴方便,我依然很少发言。随后发生的事情有“思想的境界”被关闭,这件事还颇引起了一些风波。好几个地方出现了“盗版”的思想网,供网友们下载原来思想网上的好文章之用。西祠的“思想的境界”论坛也一直保留了下来,只是再没有往日的红火。最近我在一本正式出版物中读到了作者引用李永刚兄对网络民主的观点,感慨颇多。接下来是2001年春夏之交,离某个重要的纪念日还有一两个月,网络上的不安与躁动已经开始,这时却传来“羊子的思想家园”站长杨子立等四人被捕的消息。“羊子的思想家园”是我常去的网站,在我学会用代理浏览海外的“反动”网站之后,还常常在她那里寻找可用的代理,所以我对杨子立的被捕感到特别震惊。而且随着纪念日的日趋临近,西祠网友的情绪日趋激动,“风声”也日趋紧张。比“民主论坛”激烈得多的“自由主义论坛”中存放了大量关于这个纪念日的文章,直到坛子被西祠站方关掉;几个大胆的网友被封ID;这时关于网特的传言也越来越多。这些促使我做出了一个决定,借用王小波的一句话:吾辈从今天开始说话。如果现在我不说话,以后可能就没人能够说话了。这是我发言的开始。终于进入6月了,西祠站方宣布,6月1日至7日,西祠因技术原因休站7天。 说是技术原因休站,但是网站的服务器一直开着,网友们仍然可以以各种方式“挖地道”进入胡同。到了纪念日当天,网友们都发现自己的嘴巴被封上:无法在论坛发言了。这时又有网友迅速开发出替代程序,解放了的网友纷纷发出感慨:原来嘴巴被封住的滋味是这样的!我的一篇纪念文章也得以发出。西祠的“技术性休站”休了大约有一个月。这期间据说被南京某报(西祠的服务器在南京)批判“名义上服从领导决定休站,实际上留有多个入口供反动分子进入。”这样直到有一天,西祠关闭“民主和人权”等多个时事政治类讨论版,另有一批讨论版被降级为秘密版。民版的老网友们不甘寂寞,另外找服务器做了一个接口跟西祠很像的“烟雨社区”。烟雨的优点是任何人都可以建讨论版,因此我也开了自己的文学类讨论版“发条橘子”。尽管如此,烟雨上新建的“民主与自由”版,却是整个社区当之无愧的“老大”:民版占了烟雨的绝大部分的空间。与此同时,民版网友也不满足于仅仅上网发发帖子了,我们想利用自己的力量做点实事了。烟雨是西祠的简易版,有很多不足之处,比如不能开秘密版,没有聊天室等等。于是我们回到西祠开设了一个秘密版——版的名字很不引人注目,叫做“好朋友一起来玩”,由于版号是71138,于是我们又管它叫71138版——目的是讨论我们能为中国的进步做点什么。我们决定每周五晚上8点在秘密版的聊天室里开会讨论。我不知道最早的网络会议是不是从我们开始。过了很长一段时间,我们的网络会议早已停止以后,一位网友写了一篇《光着身子开会》,意即在网络聊天室里,不必西装革履,甚至可以什么都不穿地开会,回忆这一段日子。大约两年以后,我坐在看守所里,看着电视新闻里新政府要反腐败,改革会议方式,改用网上会议,我也回想起了当时在聊天室里开会的日子。讨论中有些朋友不满足于网络社区组织的虚拟和松散,想要走下网络,成立更加严密的组织。我写了一篇文章对此提出反对意见:我不反对走下网络,但是我反对成立任何形式的严密组织,原因是新青年学会的前车之鉴。我所希望的就是像版名一样“好朋友一起来玩”,大家以网络为平台彼此交流、相互支持,以在异化和疏离的世界中获得归属感。在这个思想的指导下,我和北京的网友们搞了几次聚会:“组织大家去爬山看电影”,这是一位网友的话。一次讨论中,有网友找来了2000年6月被捕的“天网”黄琦的妻子曾丽。大家讨论如何能帮助黄琦,最后的结果是我们捐了一些钱给曾丽,因为她的生活很困难。就是这时候我写了《柿油派网虫集体向D和政府投诚》。这个帖子是一位网友的主意。我们还讨论了其它一些主意,但是都没有结果。烟雨论坛只存活了短短的两个多月就被关闭了,从此“民主与自由”便走上了在三十多个论坛上流浪的道路。而西祠的秘密版却一直存在到今天,只是再没有人气。与此同时,民版的朋友还在西祠上开了另一个秘密版:“人民日报FANS俱乐部”,后来改名叫“人民日报读报小组”。版内经常滑稽模仿“我D”搞一些D内斗争,搞点政治无厘头逗大家笑。我也在一些文章中提到过它。这个版也早已被关闭。2001年十一旅游黄金周期间,民版的网友们决定在南京搞一次跨省的大聚会,参加聚会的网友来自江苏、上海、安徽、广东、辽宁等省市。让我觉得比较遗憾的是没有北京网友参加。出于开玩笑的目的我写了一篇《西祠柿油D第一次全国代表大会在南京召开》的“报导”(其实就是把中共一大的文告拿来改头换面),贴在西祠的秘密版里。这个“报导”没过多长时间便被斑竹删掉。当时我还抱怨斑竹“过敏”,谁知一年多以后当我面对预审的时候,当问到“西祠柿油D”是怎么回事时,我只好努力解释那只是一个玩笑。由此可见他们对“组D”的敏感程度。此后的半年里,秘密版的讨论逐渐冷下去,“民主与自由”关了又开,遇到的压力之大可想而知。在这段时间我写了一些文章,认识了一些网友;除了民版以外,我还在其它一些论坛上发言,如问题与主义(后改名为学而思)、不寐论坛等;“不锈钢老鼠”也从一个名不见经传的小ID变成了“著名网友”,还当了一段时间民版和学而思的斑竹。2002年五一的旅游黄金周又快到了,民版的老朋友们又想组织一次聚会,这次我们可遇到麻烦了!五一之前,多名积极组织聚会的网友、及西祠和民版的著名网友被江苏当地国安传讯,聚会被迫取消。据被传讯过的网友说,我写的一些文章引起了国安的注意,我和几位北方网友是他们询问的重点。现在有人指责当时的一位网友被传讯时“向国安提供了很多关于老鼠的不实之词”,我要郑重声明的是,事情是这样的:这位网友确实对国安说过诸如我年龄有四五十岁或者更大、以前当过右派等等“不实之词”,但他的动机是为了保护我;他此举也许有些不负责任,但是并没有恶意,相反我是应该感谢他的。我认为他不应该因此而受到网友们的指责。听说这件事之后我被吓坏了,有一段时间没有发过帖子。可时间长了,又感到这件事的可笑。我写了“三部曲”的《不锈钢老鼠的自白书》,分别引用话剧、电影和小说作题目,来表达这件事的荒谬和解释我心中的真实想法。我又开始在网上发帖子。直到2002年9月,北师大百年校庆刚过,心理系负责学生工作的老师找我谈话,说我在互联网上发表过一些非常反动的文章,上边几次找到学校,还说我有组D的想法,是一个非法组织的重要成员等等,警告我以后不要再发那些过分的文章。当时我知道“狼”真的来了。从那之后,除了一篇关于减肥的文章以外,我没有在网上发过任何帖子,连跟贴也很少,直到2002年11月7日,我被北京市公安局刑事拘留。
2008年7月11日星期五
I have many many dreams......
there are many dreams I want to complete them.just like I want to join in the best company all over the world.and I want to be more outstanding than the people that I ever met.But at the moment I don't know how to start it.I am doing some not so challenging work.At least I want to go abroad to meet some top coder all over the world.just like some coders/architects who works in MS or google or others.........
2008-07-11,I will do some practice for topcoder
The target : win in the tc srm 410 which at
Beijing
Midnight Sat-Sun
July 19, 2008 at 12:00 Noon New York time
First , I will complete the all of the srm 409 problems and 408,407,406.
Beijing
Midnight Sat-Sun
July 19, 2008 at 12:00 Noon New York time
First , I will complete the all of the srm 409 problems and 408,407,406.
My first Englist blog
I will written my life in English here for practicing my written English and oral English.I hope you will like what I written.
I will record my topcoder practice and google code jam and other coding competition。And also I will write some about my current works in the company.I think that will very funny.Hope you all can love me and my blog~~~~~~
I will record my topcoder practice and google code jam and other coding competition。And also I will write some about my current works in the company.I think that will very funny.Hope you all can love me and my blog~~~~~~
订阅:
博文 (Atom)