<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_egmkang</title><subtitle type="text">"新的代数语言每5年就走红和过时,而我想要强调的是永恒的概念."   ------By Knuth</subtitle><id>http://feed.cnblogs.com/blog/u/29094/rss</id><updated>2012-01-20T02:03:42Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/29094/rss"/><entry><id>http://www.cnblogs.com/egmkang/archive/2012/01/18/2325474.html</id><title type="text">[C++]怎么样实现一个较快的Hash Table</title><summary type="text">我们服务器一直在用boost/sgl stl的hash table,但是从来没有考虑过其中的效率问题,虽然hash_map/unordered_map跑的可能真的比map快一些,可能应该不是你理解的那么快.其实他可以更快一些!!! 当我自己尝试着实现了一个hash table之后,我发现确实如此.这篇文章也是来说说,如何实现较快的一个. 通常的hash table都是用开链法,开放地址法来解决冲突.开链法是总容易实现的一个,而且因为效率稳定,被加入了C++11,取名unordered_map.不过效率实在不咋地. 开放地址法的hash table,我是从google-sparseha...</summary><published>2012-01-18T06:40:00Z</published><updated>2012-01-18T06:40:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2012/01/18/2325474.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2012/01/18/2325474.html"/><content type="html">&lt;p&gt;我们服务器一直在用boost/sgl stl的hash table,但是从来没有考虑过其中的效率问题,虽然hash_map/unordered_map跑的可能真的比map快一些,可能应该不是你理解的那么快.其实他可以更快一些!!!&lt;/p&gt;&#xD;
&lt;p&gt;当我自己尝试着实现了一个hash table之后,我发现确实如此.这篇文章也是来说说,如何实现较快的一个.&lt;/p&gt;&#xD;
&lt;p&gt;通常的hash table都是用开链法,开放地址法来解决冲突.开链法是总容易实现的一个,而且因为效率稳定,被加入了C++11,取名unordered_map.不过效率实在不咋地.&lt;/p&gt;&#xD;
&lt;p&gt;开放地址法的hash table,我是从google-sparsehash里面注意到的,虽然数据结构,算法导论都会讲到.网上说速度很快,我就去看了一下API,其比普通的unordered_map多了一组API:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;1.&amp;nbsp; set_empty_key/set_deleted_key&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在开链法中,所有的节点都是容器内的内容,可是开放地址法中不是的.所以需要额外的信息来维护节点的可用性信息.&lt;/p&gt;&#xD;
&lt;p&gt;当时我看到这两个API,大概就猜到内存是怎么实现的,闲来无事就是试着写了一个demo,在VC 2008下面跑的结果是,比unordered_map快一倍多;在Linux x64 gcc 4.4下面的结果是,比unordered_map快了将近1倍.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;2. 高性能的hash table必须是开放地址法的&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这么说,是有原因的.链表的特性就是容易删除,容易插入.可是hash table不需要这些特性,hash table只需要快.可以链表这东西,偏偏做不到快速定位,虽然你知道有下一个节点,但是你不知道下一个节点的准确位置,经常会造成缓存未命中,浪费大量时间.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;3. bucket的容量&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;bucket的容量也是影响hash table性能的一个因素.无数的数据结构和算法书籍,都教导大家,通过质数取余数,可以获得比较好的下标分布.可是,无论是除法还是乘法,消耗都是相当高的.十几个或者几十个时钟周期,始终比不上一两个时钟周期快.所以,高性能的hash table必须要把bucket的容量设置成2^n.google-sparsehash里面初始容量是32.扩容的话,都是直接左移;算下标的话,都是(容量-1) &amp;amp; hash_value,简单的一个位运算搞定.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;4. 正确实现find_position&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我自己实现的hash table,是线性探测法的.所以find position也是比较简单,就是通过hash value和掩码,获取到其实下标,然后一个一个test.需要把buckets当作是环形的,否则buckets最末位的数据冲突就会不好搞.(我当时没有考虑这一点,直接给他扩容了.....)&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;5. 对象模型&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;不同的Key和Value模型,可以导致你对Hash Table的不同实现.简单的说,在C里面,你可以不用考虑Key和Value的生命周期(:D),但是C++里面,你不得不考虑Key,Value的生命周期问题.你不能做一个假设,key和value都是简单数据类型.一个int映射到一个对象,这种经常会用到的.&lt;/p&gt;&#xD;
&lt;p&gt;所以,erase一个key的时候,需要把key设置成deleted,然后还要把value重置一遍.如果没有重置,对象所引用的内存有可能就会被泄露.&lt;/p&gt;&#xD;
&lt;p&gt;这引发了我另外一个想法,就是通过模板,来特化Value的reset行为.因为不是所有的Value都是需要被重置的,只有那些复杂对象,才需要.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;6. 可以考虑缓冲hash value&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;如果key都是简单数据,而非string或者复杂的数据类型,缓冲是没有任何意义的,因为hash value可以被快速的计算出来;但是当key是char*,或者一些复杂的数据类型,缓冲就会变的有意义.而且缓冲更有利于重排,容器扩容的时候速度会更快一些.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;7. 考虑使用C的内存分配器&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;尽量不要使用C++的new/delete来分配内存.new,delete会有对象的构造,析构过程,这可能不是你所希望的.针对key和value数据类型的不同,你可能会有自己的特有的构造,析构过程.而且,C的内存分配器,同样可以被一些第三方库优化,比如tcmalloc/jemalloc等.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;8. 选一个好的Hash函数&lt;/strong&gt;(&lt;strong&gt;这是最重要的&lt;/strong&gt;)&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;差不多就这些.后来自己写的那个demo,性能差不多和google-sparsehash一样...&lt;/p&gt;&#xD;
&lt;p&gt;参考:&lt;/p&gt;&#xD;
&lt;p&gt;1. 算法导论&lt;/p&gt;&#xD;
&lt;p&gt;2. 计算机程序设计艺术&lt;/p&gt;&#xD;
&lt;p&gt;3. google-sparsehash dense_hash_map的实现, &lt;a href="http://code.google.com/p/google-sparsehash" target="_blank"&gt;http://code.google.com/p/google-sparsehash&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2325474.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2012/01/18/2325474.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2012/01/18/2325468.html</id><title type="text">[OT]回顾2011,写在2012初</title><summary type="text">2011年都干了些啥....读书:1. 聪明的投资者2. 超级数字天才3. 西游记4. 程序开发心理学5. Unix网络编程6. Unix环境高级编程...或者还有其他的,暂时不记得了技术???....好像没干啥,就天天写代码....搞搞C++,Valgrind,Lua,宕机等等2012年,希望自己可以认真的去写写网络程序,虽然号称是写服务器的,但是从来没写过网络程序;希望可以认真的去看看几个开源的代码,研究一下;over</summary><published>2012-01-18T05:43:00Z</published><updated>2012-01-18T05:43:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2012/01/18/2325468.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2012/01/18/2325468.html"/><content type="html">&lt;p&gt;2011年都干了些啥....&lt;/p&gt;&#xD;
&lt;p&gt;读书:&lt;/p&gt;&#xD;
&lt;p&gt;1. 聪明的投资者&lt;/p&gt;&#xD;
&lt;p&gt;2. 超级数字天才&lt;/p&gt;&#xD;
&lt;p&gt;3. 西游记&lt;/p&gt;&#xD;
&lt;p&gt;4. 程序开发心理学&lt;/p&gt;&#xD;
&lt;p&gt;5. Unix网络编程&lt;/p&gt;&#xD;
&lt;p&gt;6. Unix环境高级编程&lt;/p&gt;&#xD;
&lt;p&gt;...或者还有其他的,暂时不记得了&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;技术???....好像没干啥,就天天写代码....&lt;/p&gt;&#xD;
&lt;p&gt;搞搞C++,Valgrind,Lua,宕机等等&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;2012年,&lt;/p&gt;&#xD;
&lt;p&gt;希望自己可以认真的去写写网络程序,虽然号称是写服务器的,但是从来没写过网络程序;&lt;/p&gt;&#xD;
&lt;p&gt;希望可以认真的去看看几个开源的代码,研究一下;&lt;/p&gt;&#xD;
&lt;p&gt;over&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2325468.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2012/01/18/2325468.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/12/27/2303419.html</id><title type="text">[投资]写在11年末</title><summary type="text">大学还没毕业,买了一些建行,一些交行..... 虽然现在还认为那些股票不错,不过终究发生过换股,全换成浦发,古井贡酒,还有鲁泰,出现了一些亏损,记录如下: 其中塔牌,华兰生物是做短线亏损,其他几个本来打算做长线,后来发现收益较好的品种,换股.... 股票名称 交易亏损(RMB) 农业银行 165.95 交通银行 1675.99 建设银行 288.00 三一重工 290.66 苏宁电器 677.41 塔牌集团 281.30 华兰生物 65.72 一共亏损:3445.82. 谨记.</summary><published>2011-12-27T05:27:00Z</published><updated>2011-12-27T05:27:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/12/27/2303419.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/12/27/2303419.html"/><content type="html">&lt;p&gt;大学还没毕业,买了一些建行,一些交行.....&lt;/p&gt;&#xD;
&lt;p&gt;虽然现在还认为那些股票不错,不过终究发生过换股,全换成浦发,古井贡酒,还有鲁泰,出现了一些亏损,记录如下:&lt;/p&gt;&#xD;
&lt;p&gt;其中塔牌,华兰生物是做短线亏损,其他几个本来打算做长线,后来发现收益较好的品种,换股....&lt;/p&gt;&#xD;
&lt;p&gt;股票名称 &amp;nbsp;&amp;nbsp; &amp;nbsp;交易亏损(RMB)&lt;br /&gt;　　农业银行 &amp;nbsp;&amp;nbsp; &amp;nbsp;　　165.95&lt;br /&gt;　　交通银行 &amp;nbsp;&amp;nbsp; &amp;nbsp;　　1675.99&lt;br /&gt;　　建设银行 &amp;nbsp;&amp;nbsp; &amp;nbsp;　　288.00&lt;br /&gt;　　三一重工 &amp;nbsp;&amp;nbsp; &amp;nbsp;　　290.66&lt;br /&gt;　　苏宁电器 &amp;nbsp;&amp;nbsp; &amp;nbsp;　　677.41&lt;br /&gt;　　塔牌集团 &amp;nbsp;&amp;nbsp; &amp;nbsp;　　281.30&lt;br /&gt;　　华兰生物 &amp;nbsp;&amp;nbsp; &amp;nbsp;　　65.72&lt;/p&gt;&#xD;
&lt;p&gt;一共亏损:3445.82.&lt;/p&gt;&#xD;
&lt;p&gt;谨记.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2303419.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/12/27/2303419.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/10/25/2224561.html</id><title type="text">[C++]运行时,如何确保一个对象是只读的</title><summary type="text">相信很多人碰到过一个问题,就是代码太多了,不知道在哪里把这个对象给修改掉了.这个其实有两种办法的.1. 在调试的时候,可以下数据断点. gdb有watch断点.比如gdb&amp;gt;watch *(int*)0x12433,要记住,如果想要一只监视这个数据,就要用地址,否则过了这个scope,数据断点就无效了,还有就是,监视的值如果用内置数据类型可以表达的话,是有硬件断点的,否则效率茫茫低.....2. 运行的时候,本文主要讲这个. 先来回顾一下,我们都知道一个exec,都有好几个段,比如代码段,数据段等.这些段是有读写属性的,例如代码段只可以读,栈段是可以读写~~.那么我们就想把一个对象塞到一个</summary><published>2011-10-25T14:55:00Z</published><updated>2011-10-25T14:55:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/10/25/2224561.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/10/25/2224561.html"/><content type="html">&lt;p&gt;相信很多人碰到过一个问题,就是代码太多了,不知道在哪里把这个对象给修改掉了.这个其实有两种办法的.&lt;/p&gt;&#xD;
&lt;p&gt;1. 在调试的时候,可以下数据断点.&lt;/p&gt;&#xD;
&lt;p&gt;gdb有watch断点.比如gdb&amp;gt;watch *(int*)0x12433,要记住,如果想要一只监视这个数据,就要用地址,否则过了这个scope,数据断点就无效了,还有就是,监视的值如果用内置数据类型可以表达的话,是有硬件断点的,否则效率茫茫低.....&lt;/p&gt;&#xD;
&lt;p&gt;2. 运行的时候,本文主要讲这个.&lt;/p&gt;&#xD;
&lt;p&gt;先来回顾一下,我们都知道一个exec,都有好几个段,比如代码段,数据段等.这些段是有读写属性的,例如代码段只可以读,栈段是可以读写~~.那么我们就想把一个对象塞到一个不可以写的段里面,比如.text段....(事实上,我塞进去过,只不过会有警告)&lt;/p&gt;&#xD;
&lt;p&gt;这个异常暴力,而且预留余地太小,不太适合.&lt;/p&gt;&#xD;
&lt;p&gt;现在操作系统都是段模式+分页模式来管理内存的.段模式走不通,换页模式,找个办法设置内存页的属性~~.&lt;/p&gt;&#xD;
&lt;p&gt;非常幸运,Linux下面有mprotect系统调用,可以运行时设置内存页的读写属性,唯一的要求是内存需要4K对齐,浪费了一点.&lt;/p&gt;&#xD;
&lt;p&gt;OK,让我们来看mprotect的man page:&lt;a target="_blank" href="http://linux.die.net/man/2/mprotect"&gt;http://linux.die.net/man/2/mprotect&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;签名很简答:int mprotect(const void *addr, size_t len, int prot);&lt;/p&gt;&#xD;
&lt;p&gt;一个地址,一个内存的长度,另外就是读写属性,返回调用的结果,成功返回0,失败返回其他数字.&lt;/p&gt;&#xD;
&lt;p&gt;顺便看看man page中的例子,里面有一个技巧,就是搞到一个4K对齐的内存~~ 通过 ( ptr + 4096 - 1 ) &amp;amp; ~(4096 - 1)搞到的&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;#include &amp;lt;stdio.h&amp;gt;&#xD;
#include &amp;lt;stdlib.h&amp;gt;&#xD;
#include &amp;lt;errno.h&amp;gt;&#xD;
#include &amp;lt;sys/mman.h&amp;gt;&#xD;
#include &amp;lt;limits.h&amp;gt;    /* for PAGESIZE */&#xD;
#ifndef PAGESIZE&#xD;
#define PAGESIZE 4096&#xD;
#endif&#xD;
int&#xD;
main(void)&#xD;
{&#xD;
    char *p;&#xD;
    char c;&#xD;
    /* Allocate a buffer; it will have the default&#xD;
       protection of PROT_READ|PROT_WRITE. */&#xD;
    p = malloc(1024+PAGESIZE-1);&#xD;
    if (!p) {&#xD;
        perror("Couldn't malloc(1024)");&#xD;
        exit(errno);&#xD;
    }&#xD;
    /* Align to a multiple of PAGESIZE, assumed to be a power of two */&#xD;
    p = (char *)(((int) p + PAGESIZE-1) &amp;amp; ~(PAGESIZE-1));&#xD;
    c = p[666];         /* Read; ok */&#xD;
    p[666] = 42;        /* Write; ok */&#xD;
    /* Mark the buffer read-only. */&#xD;
    if (mprotect(p, 1024, PROT_READ)) {&#xD;
        perror("Couldn't mprotect");&#xD;
        exit(errno);&#xD;
    }&#xD;
    c = p[666];         /* Read; ok */&#xD;
    p[666] = 42;        /* Write; program dies on SIGSEGV */&#xD;
    exit(0);&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;至此,我们就可以运行时,保证一个对象不可以写,写的话,core掉:-D&lt;/p&gt;&#xD;
&lt;p&gt;PS:&lt;/p&gt;&#xD;
&lt;p&gt;希望windows下也有类似的系统调用,Windows下有VirtualProtect,有兴趣的朋友研究一下&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2224561.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/10/25/2224561.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/10/25/2224529.html</id><title type="text">[C++]怎样将C++对象分配在堆/栈上</title><summary type="text">相信一些朋友也碰见过这样的面试题目,本文尝试着给出解答.1. 分配对象在堆上 那么,必然要禁止对象在栈上面分配.一个很简单的办法,就是构造函数私有化(提供额外的接口生成对象),那么在栈上面就不可以分配.可是我们还需要这个对象要被析构,那么可以提供一个接口,显式的释放掉这个接口,也就是说delete也得给他禁掉~~~ 考虑另外一个问题,C++有placement new,我自己new一块内存,然后在你这上面构造.问题就变得很恶心,看来我们只有把new,delete都给他禁掉... 好了,我们现在知道该怎么做:createInstance()接口产生对象dispose()接口销毁对象new/...</summary><published>2011-10-25T14:40:00Z</published><updated>2011-10-25T14:40:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/10/25/2224529.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/10/25/2224529.html"/><content type="html">&lt;p&gt;相信一些朋友也碰见过这样的面试题目,本文尝试着给出解答.&lt;/p&gt;&#xD;
&lt;p&gt;1. 分配对象在堆上&lt;/p&gt;&#xD;
&lt;p&gt;那么,必然要禁止对象在栈上面分配.一个很简单的办法,就是构造函数私有化(提供额外的接口生成对象),那么在栈上面就不可以分配.可是我们还需要这个对象要被析构,那么可以提供一个接口,显式的释放掉这个接口,也就是说delete也得给他禁掉~~~&lt;/p&gt;&#xD;
&lt;p&gt;考虑另外一个问题,C++有placement new,我自己new一块内存,然后在你这上面构造.问题就变得很恶心,看来我们只有把new,delete都给他禁掉...&lt;/p&gt;&#xD;
&lt;p&gt;好了,我们现在知道该怎么做:&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;createInstance()接口产生对象&lt;/li&gt;&#xD;
&lt;li&gt;dispose()接口销毁对象&lt;/li&gt;&#xD;
&lt;li&gt;new/delete操作符全部不可见&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;来看我们的代码:&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;class HeapObject{&#xD;
public:&#xD;
	static HeapObject* createInstance()&#xD;
	{&#xD;
		return new HeapObject;&#xD;
	}&#xD;
	void dispose()&#xD;
	{&#xD;
		delete this;&#xD;
	}&#xD;
protected:&#xD;
	HeapObject(){}&#xD;
	~HeapObject(){}&#xD;
&#xD;
	static void* operator new (std::size_t size) throw (std::bad_alloc)&#xD;
	{&#xD;
		return ::operator new(size);&#xD;
	}&#xD;
	static void* operator new (std::size_t size, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void* operator new (std::size_t size, void* ptr) throw();&#xD;
	static void* operator new[] (std::size_t size) throw (std::bad_alloc);&#xD;
	static void* operator new[] (std::size_t size, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void* operator new[] (std::size_t size, void* ptr) throw();&#xD;
&#xD;
	static void operator delete (void* ptr) throw ()&#xD;
	{&#xD;
		::operator delete(ptr);&#xD;
	}&#xD;
	static void operator delete (void* ptr, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void operator delete (void* ptr, void* voidptr2) throw();&#xD;
&#xD;
	static void operator delete[] (void* ptr) throw ();&#xD;
	static void operator delete[] (void* ptr, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void operator delete[] (void* ptr, void* voidptr2) throw();&#xD;
};&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;2. 分配对象在栈上&lt;/p&gt;&#xD;
&lt;p&gt;只能分配对象在栈上面,那么new显然是不能用的,否则就是在堆上面分配对象了,理所当然,delete也得禁掉.&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;class StackObject&#xD;
{&#xD;
public:&#xD;
	StackObject(){}&#xD;
	~StackObject(){}&#xD;
protected:&#xD;
	static void* operator new (std::size_t size) throw (std::bad_alloc);&#xD;
	static void* operator new (std::size_t size, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void* operator new (std::size_t size, void* ptr) throw();&#xD;
	static void* operator new[] (std::size_t size) throw (std::bad_alloc);&#xD;
	static void* operator new[] (std::size_t size, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void* operator new[] (std::size_t size, void* ptr) throw();&#xD;
&#xD;
	static void operator delete (void* ptr) throw ();&#xD;
	static void operator delete (void* ptr, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void operator delete (void* ptr, void* voidptr2) throw();&#xD;
&#xD;
	static void operator delete[] (void* ptr) throw ();&#xD;
	static void operator delete[] (void* ptr, const std::nothrow_t&amp;amp; nothrow_constant) throw();&#xD;
	static void operator delete[] (void* ptr, void* voidptr2) throw();&#xD;
};&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;比较需要注意的地方是,new/delete有多个重载,算上[]的话,就是3*2*2=12个操作符.....&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2224529.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/10/25/2224529.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/09/27/2193096.html</id><title type="text">[Lua]用__index/__newindex来限制访问</title><summary type="text">网友问了一个问题,说对象A在内部可以修改HP.外部对象只能访问对象A的HP,不能修改.这东西其实可以用__index和__newindex来实现.__index指向对象A,这样就可以访问;__newindex重写,修改hp的话,就禁止.就可以完成他的需求.下面给出简单的代码:function cannotModifyHp(object) local proxy = {} local mt = { __index = object,	__newindex = function(t,k,v) if k ~= &amp;quot;hp&amp;quot; then object[k] = v en...</summary><published>2011-09-27T06:16:00Z</published><updated>2011-09-27T06:16:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/09/27/2193096.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/09/27/2193096.html"/><content type="html">&lt;p&gt;网友问了一个问题,说对象A在内部可以修改HP.外部对象只能访问对象A的HP,不能修改.&lt;/p&gt;&#xD;
&lt;p&gt;这东西其实可以用__index和__newindex来实现.&lt;/p&gt;&#xD;
&lt;p&gt;__index指向对象A,这样就可以访问;&lt;/p&gt;&#xD;
&lt;p&gt;__newindex重写,修改hp的话,就禁止.就可以完成他的需求.&lt;/p&gt;&#xD;
&lt;p&gt;下面给出简单的代码:&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;function cannotModifyHp(object)&#xD;
    local proxy = {}&#xD;
    local mt = {&#xD;
    	__index = object,&#xD;
	__newindex = function(t,k,v)&#xD;
	    if k ~= "hp" then&#xD;
		object[k] = v&#xD;
	    end&#xD;
	end&#xD;
    }&#xD;
    setmetatable(proxy,mt)&#xD;
    return proxy&#xD;
end&#xD;
&#xD;
object = {hp = 10,age = 11}&#xD;
function object.sethp(self,newhp)&#xD;
	self.hp = newhp&#xD;
end&#xD;
&#xD;
o = cannotModifyHp(object)&#xD;
&#xD;
o.hp = 100&#xD;
print(o.hp)&#xD;
&#xD;
o:sethp(111)&#xD;
print(o.hp)&#xD;
&#xD;
object:sethp(100)&#xD;
print(o.hp)&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;PS:&lt;/p&gt;&#xD;
&lt;p&gt;好长时间没写过lua了,都快忘了&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2193096.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/09/27/2193096.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/09/26/2189548.html</id><title type="text">[C++]野指针的产生以及应对办法</title><summary type="text">很大程度上,野指针都是因为编码不善,习惯不好所产生的.要解决野指针,就要养成好习惯,不要动不动就public数据成员,所有的数据访问都抽象成接口,最好只在一个地方delete数据.前段时间游戏技术测试,down机无限,搞的很头疼.后来用valgrind的memcheck工具,找到很多野指针.valgrind很好用,除了有一点慢:-)valgrind --tool=memcheck --leak-check=full --log-file=./log_file.log --showpossibly-lost=no --malloc-fill=0xff --free-fill=0x11 ./exe</summary><published>2011-09-26T14:51:00Z</published><updated>2011-09-26T14:51:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/09/26/2189548.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/09/26/2189548.html"/><content type="html">&lt;p&gt;很大程度上,野指针都是因为编码不善,习惯不好所产生的.&lt;/p&gt;&#xD;
&lt;p&gt;要解决野指针,就要养成好习惯,不要动不动就public数据成员,所有的数据访问都抽象成接口,最好只在一个地方delete数据.&lt;/p&gt;&#xD;
&lt;p&gt;前段时间游戏技术测试,down机无限,搞的很头疼.后来用valgrind的memcheck工具,找到很多野指针.&lt;/p&gt;&#xD;
&lt;p&gt;valgrind很好用,除了有一点慢:-)&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;valgrind --tool=memcheck --leak-check=full --log-file=./log_file.log --showpossibly-lost=no --malloc-fill=0xff --free-fill=0x11 ./execFile&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;用上面的语句,就可以启动一个execFile,顺便把所有malloc内存设置成0xff,free内存设置成0x11,还会统计内存泄露(在log_file.log内).简单易用.&lt;/p&gt;&#xD;
&lt;p&gt;然后么,一个一个去fix....&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;跟同学交流,他们那边有一个办法,去解决这个野指针问题,也是很巧妙的,不敢独享:-D&lt;/p&gt;&#xD;
&lt;p&gt;A对象会被n个其他对象B引用,就是其他n个对象B会持有指向A的指针.&lt;/p&gt;&#xD;
&lt;p&gt;如果A被delete,其他n个对象B指向A的指针的内存已经不可访问,这个时候访问那块内存,就会发生未定义行为.&lt;/p&gt;&#xD;
&lt;p&gt;天知道会怎么样!!!也许会down掉,也许不会.&lt;/p&gt;&#xD;
&lt;p&gt;他们是搞的:&lt;/p&gt;&#xD;
&lt;p&gt;1) 对象B对A的引用,A自己会保存一份记录,标记有对象B引用过自己&lt;/p&gt;&#xD;
&lt;p&gt;2) 对象B析构,会通知A,这个时候,A会去除B对自己的引用的标记&lt;/p&gt;&#xD;
&lt;p&gt;3) A析构,A会把所有指向自己的指针,设置成NULL&lt;/p&gt;&#xD;
&lt;p&gt;这是基本思想.&lt;/p&gt;&#xD;
&lt;p&gt;下面给出简单的实现,非线程安全,有什么问题可以提出...&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;#ifndef __REFERABLE_H__&#xD;
#define __REFERABLE_H__&#xD;
&#xD;
#include &amp;lt;vector&amp;gt;&#xD;
#include "ref_ptr.h"&#xD;
&#xD;
template&amp;lt;typename T&amp;gt;&#xD;
class referable&#xD;
{&#xD;
public:    &#xD;
    typedef referable** RefAddress;&#xD;
    virtual ~referable()&#xD;
    {&#xD;
        for (container_iter iter = m_references.begin();&#xD;
            iter != m_references.end();&#xD;
            ++iter)&#xD;
        {&#xD;
            **iter = NULL; &#xD;
        }&#xD;
    }&#xD;
private:&#xD;
    typedef typename std::vector&amp;lt;RefAddress&amp;gt; container_type;&#xD;
    typedef typename container_type::iterator container_iter;&#xD;
&#xD;
    friend class ref_ptr&amp;lt;T&amp;gt;;&#xD;
    void on_reg(RefAddress addr)&#xD;
    {&#xD;
        for (container_iter iter = m_references.begin();&#xD;
            iter != m_references.end();&#xD;
            ++iter)&#xD;
        {&#xD;
            if(*iter == addr) return;&#xD;
        }&#xD;
        m_references.push_back(addr);&#xD;
    }&#xD;
    void on_unreg(RefAddress addr)&#xD;
    {&#xD;
        for (container_iter iter = m_references.begin();&#xD;
            iter != m_references.end();)&#xD;
        {&#xD;
            if(*iter == addr)&#xD;
                iter = m_references.erase(iter);&#xD;
            else&#xD;
                ++iter;&#xD;
        }&#xD;
    }&#xD;
private:&#xD;
    container_type m_references;&#xD;
};&#xD;
#endif&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;#ifndef __REFERENCE_POINTER_H__&#xD;
#define __REFERENCE_POINTER_H__&#xD;
#include "referable.h"&#xD;
&#xD;
template&amp;lt;typename T&amp;gt;&#xD;
class ref_ptr&#xD;
{&#xD;
public:&#xD;
    ref_ptr():m_ptr(NULL){}&#xD;
    ref_ptr(T *ptr):m_ptr(ptr)&#xD;
    {&#xD;
        add_ref();&#xD;
    }&#xD;
    ref_ptr(const ref_ptr&amp;lt;T&amp;gt;&amp;amp; ref):m_ptr(ref.m_ptr)&#xD;
    {&#xD;
        add_ref();&#xD;
    }&#xD;
    virtual ~ref_ptr()&#xD;
    {&#xD;
        remove_ref();&#xD;
    }&#xD;
&#xD;
    ref_ptr&amp;lt;T&amp;gt;&amp;amp; operator = (const ref_ptr&amp;lt;T&amp;gt;&amp;amp; ref)&#xD;
    {&#xD;
        if(this == &amp;amp;ref) return *this;&#xD;
        remove_ref();&#xD;
        m_ptr = ref.m_ptr;&#xD;
        add_ref();&#xD;
        return *this;&#xD;
    }&#xD;
    ref_ptr&amp;lt;T&amp;gt;&amp;amp; operator = (T *ptr)&#xD;
    {&#xD;
        if(m_ptr != ptr)&#xD;
        {&#xD;
            remove_ref();&#xD;
            m_ptr = ptr;&#xD;
            add_ref();&#xD;
        }&#xD;
        return *this;&#xD;
    }&#xD;
public:&#xD;
    T*  operator-&amp;gt;() const { return m_ptr; }&#xD;
    T&amp;amp;  operator*() const { return *m_ptr; }&#xD;
    operator T*() const { return m_ptr; }&#xD;
    operator bool() const { return m_ptr; }&#xD;
private:&#xD;
    void add_ref()&#xD;
    {&#xD;
        if(m_ptr) ((referable&amp;lt;T&amp;gt;*)m_ptr)-&amp;gt;on_reg((referable&amp;lt;T&amp;gt;**)&amp;amp;m_ptr);&#xD;
    }&#xD;
    void remove_ref()&#xD;
    {&#xD;
        if(m_ptr) ((referable&amp;lt;T&amp;gt;*)m_ptr)-&amp;gt;on_unreg((referable&amp;lt;T&amp;gt;**)&amp;amp;m_ptr);&#xD;
        m_ptr = NULL;&#xD;
    }&#xD;
&#xD;
private:&#xD;
    T* m_ptr;&#xD;
};&#xD;
&#xD;
#endif&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;测试代码:&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;class object : public referable&amp;lt;object&amp;gt;&#xD;
{&#xD;
public:&#xD;
    int x;&#xD;
};&#xD;
&#xD;
void test()&#xD;
{&#xD;
    object *a = new object;&#xD;
    object *a1 = new object;&#xD;
    ref_ptr&amp;lt;object&amp;gt; b = a;&#xD;
    a-&amp;gt;x = 10;&#xD;
    assert(b &amp;amp;&amp;amp; b-&amp;gt;x == 10);&#xD;
&#xD;
    delete a;&#xD;
    assert(!b);&#xD;
&#xD;
    b = a1;&#xD;
    assert(b);&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这个东西看上去还不错.&lt;/p&gt;&#xD;
&lt;p&gt;不过习惯还是很重要滴&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;PS:&lt;/p&gt;&#xD;
&lt;p&gt;一般引用都是只有四五个,所以vector性能足够好,我测试过~~&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2189548.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/09/26/2189548.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/08/13/2125500.html</id><title type="text">[投资]浦发银行的价值投资</title><summary type="text">CPI那么高,为了抗通胀,我买了股票,号称是价值投资:-),可是一直没有算过具体能有多少收益....今天算了一下浦发银行的收益,不算不知道,一算吓一跳啊.去年年报每股净资产8.57RMB,今年由于分割了股票,所以每股净资产大约是(8.99+0.42)/1.3 = 7.2RMB,作为起始每股净资产然后假设每年的净资产收益率为15%,去年是15.59%,据以往历史,15%的净资产收益率还是比较容易达到的.算算5年,10年后,浦发的净资产有多少:7.2(1+0.15)^5 = 14.487.2*(1+0.15)^10 = 29.12银行牛市时,PB会比较高一点,3倍算是比较高的,那么大约可以估算出1</summary><published>2011-08-13T11:22:00Z</published><updated>2011-08-13T11:22:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/08/13/2125500.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/08/13/2125500.html"/><content type="html">&lt;p&gt;CPI那么高,为了抗通胀,我买了股票,号称是价值投资:-),可是一直没有算过具体能有多少收益....&lt;/p&gt;&#xD;
&lt;p&gt;今天算了一下浦发银行的收益,不算不知道,一算吓一跳啊.&lt;/p&gt;&#xD;
&lt;p&gt;去年年报每股净资产8.57RMB,今年由于分割了股票,所以每股净资产大约是(8.99+0.42)/1.3 = 7.2RMB,作为起始每股净资产&lt;/p&gt;&#xD;
&lt;p&gt;然后假设每年的净资产收益率为15%,去年是15.59%,据以往历史,15%的净资产收益率还是比较容易达到的.&lt;/p&gt;&#xD;
&lt;p&gt;算算5年,10年后,浦发的净资产有多少:&lt;/p&gt;&#xD;
&lt;p&gt;7.2(1+0.15)^5&amp;nbsp; = 14.48&lt;/p&gt;&#xD;
&lt;p&gt;7.2*(1+0.15)^10 = 29.12&lt;/p&gt;&#xD;
&lt;p&gt;银行牛市时,PB会比较高一点,3倍算是比较高的,那么大约可以估算出10年后浦发的合理估值是大约60元;如果能达到8倍PB,那就是240RMB.&lt;/p&gt;&#xD;
&lt;p&gt;浦发达到过8倍PB哈:-)&lt;/p&gt;&#xD;
&lt;p&gt;爱股网有一堆做价值投资的网游,有兴趣的话进去看看&lt;br /&gt;&lt;a target="_blank" href="http://www.iguuu.com/?fromuser=egmkang"&gt;http://www.iguuu.com/?fromuser=egmkang&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2125500.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/08/13/2125500.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/07/16/2108078.html</id><title type="text">[vim]我的vim配置</title><summary type="text">set nocompatibleset backspace=indent,eol,startset nobackupset history=50set rulerset showcmdset showmatchset hlsearchset incsearchset ignorecasesyntax onfiletype plugin indent onautocmd FileType text setlocalset autoindentset cindentset numberset expandtabset tabstop=4set shiftwidth=4set nowrapset l</summary><published>2011-07-16T03:16:00Z</published><updated>2011-07-16T03:16:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/07/16/2108078.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/07/16/2108078.html"/><content type="html">&lt;div &gt;&#xD;
&lt;pre &gt;set nocompatible&#xD;
set backspace=indent,eol,start&#xD;
set nobackup&#xD;
set history=50&#xD;
set ruler&#xD;
set showcmd&#xD;
&#xD;
set showmatch&#xD;
set hlsearch&#xD;
set incsearch&#xD;
set ignorecase&#xD;
&#xD;
syntax on&#xD;
filetype plugin indent on&#xD;
autocmd FileType text setlocal&#xD;
&#xD;
set autoindent&#xD;
set cindent&#xD;
set number&#xD;
set expandtab&#xD;
set tabstop=4&#xD;
set shiftwidth=4&#xD;
set nowrap&#xD;
&#xD;
set listchars=tab:&amp;gt;\ ,trail:-&#xD;
set list&#xD;
&#xD;
set path+=STL_PAT&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&lt;/div&gt;&#xD;
&lt;div&gt;&lt;a href="http://files.cnblogs.com/egmkang/_vimrc.js"&gt;vimrc地址&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2108078.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/07/16/2108078.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/egmkang/archive/2011/06/19/2084652.html</id><title type="text">[转载]一些鲜为人知的编程真相</title><summary type="text">1. 一个程序员用在写程序上的时间大概占他的工作时间的10-20%，大部分的程序员每天大约能写出10-12行的能进入最终的产品的代码 — —不管他的技术水平有多高。 好的程序员花去90%的时间在思考、研究和实验，来找出最优方案。差的程序员花去90%的时间在调试问题程序、盲目的修改程序，期望某种写法能可行。“一个卓越的车床工可以要求比一个一般的车床工多拿数倍高的工资，但一个卓越的软件写手的价值会10000倍于一个普通的写手。”——比尔 盖茨 2. 一个优秀的程序员的效率会是一个普通的程序员的十倍之上。一个伟大的程序员的效率会是一个普通程序员的20-100倍。这不是夸张 — — 1960年以来的.</summary><published>2011-06-19T06:50:00Z</published><updated>2011-06-19T06:50:00Z</updated><author><name>egmkang</name><uri>http://www.cnblogs.com/egmkang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/egmkang/archive/2011/06/19/2084652.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/egmkang/archive/2011/06/19/2084652.html"/><content type="html">&lt;p&gt;1. 一个程序员用在写程序上的时间大概占他的工作时间的10-20%，大部分的程序员每天大约能写出10-12行的能进入最终的产品的代码 &amp;mdash; &amp;mdash;不管他的技术水平有多高。 好的程序员花去90%的时间在思考、研究和实验，来找出最优方案。差的程序员花去90%的时间在调试问题程序、盲目的修改程序，期望某种写法能可行。&amp;ldquo;一个卓越的车床工可以要求比一个一般的车床工多拿数倍高的工资，但一个卓越的软件写手的价值会10000倍于一个普通的写手。&amp;rdquo;&amp;mdash;&amp;mdash;比尔 盖茨&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2. 一个优秀的程序员的效率会是一个普通的程序员的十倍之上。一个伟大的程序员的效率会是一个普通程序员的20-100倍。这不是夸张 &amp;mdash; &amp;mdash; 1960年以来的无数研究都一致的证明了这一点。一个差的程序员不仅仅是没效率 &amp;mdash; &amp;mdash; 他不仅不能完成任务，写出的大量代码也让别人头痛的没法维护。&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3. 伟大的程序员只花很少的时间去写代码&amp;mdash;&amp;mdash;至少指那些最终形成产品的代码。那些要花掉大量时间写代码的程序员都是太懒惰，太自大，太傲慢，不屑用现有的方案去解决老问题。伟大的程序员的精明之处在 于懂得欣赏和重复利用通用模式。好的程序员并不害怕经常的重构（重写）他们的代码以求达到最好效果。差的程序员写的代码缺乏整体概念，冗余，没有层次，没 有模式，导致很难重构。把这些代码扔掉重做也比修改起来容易。&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4. 软件遵循熵的定律，跟其它所有东西一样。持续的变更会导致软件腐烂，腐蚀掉对原始设计的完整性概念。软件的腐烂是不可避免的，但程序员在开发软件时 没有考虑完整性，将会使软件腐烂的如此之快，以至于软件在还没有完成之前就已经毫无价值了。软件完整性上的熵变可能是软件项目失败最常见的原因。（第二大 常见失败原因是做出的不是客户想要的东西。）软件腐烂使开发进度呈指数级速度放缓，大量的软件在失败之前都是面对着突增的时间要求和资金预算。&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5. 2004年的一项研究表明大多数的软件项目（51%）会在关键功能上失败，其中15%是完全的失败。这比1994年前有很大的改进，当时是31%。&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6. 尽管大多数软件都是团体开发的，但这并不是一项民/主的活动。通常，一个人负责设计，其他人负责实现细节。&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 7. 编程是个很难的工作。是一种剧烈的脑力劳动。好的程序员7&amp;times;24小时的思考他们的工作。他们最重要的程序都是在淋浴时、睡梦中写成的。因为这最重要的工作都是在远离键盘的情况下完成的，所以软件工程不可能通过增加在办公室的工作时间或增加人手来加快进度。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;原文链接:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a target="_blank" href="http://www.jobbole.com/entry.php/334"&gt;http://www.jobbole.com/entry.php/334&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/egmkang/aggbug/2084652.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/egmkang/archive/2011/06/19/2084652.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
