春节期间一次用手机上网无意间发现了这本书,说起来还得感谢智能手机的发展,有时候还是很方便的。当时随便的翻了几页,于是我停不下来了,因为我发现原来我不知道的东西太多了。

我第一次接触STL的时候大约在7年前,那个时候刚从C语言转到C++,记得那个时候知道了STL vector, list, map, 但是只是把这些东西当作C++的语法,一带而过,用的时候查查文档,只要逻辑和结果对了就OK,到处是for循环,到处是迭代器,现在回想起来的感触是:没文化,真可怕。

第二次我想深入学习STL的时候是研究生毕业以后,记得那个时候刚入行,公司的产品出现了一个问题,是关于STL 的一个容器的erase() 方法调用问题,自己搞了半天才看懂,原来这一个特殊的情况下,这种用法有问题。为了扫清这类问题,我决定深入的学习一下STL。当时找到了一本侯捷翻译的《STL 源码剖析》,说实话,这本书写的真不错,但是他写的有点枯燥,迭代器,分配器你没点坚定的毅力说不定就败给他了,我花了一个月的时间(下班后) 才啃完这本书,不敢说100% 扫平,80%还是有的,但是当我读完的时候,我发现这并不是我想要的,我虽然理解了作者要表达的东西,读懂了分配器,迭代器的原理,但是在我的工作中用到的地方并不多。

第三次,也就是这次,当我看到《Effective STL》的时候,我的感触是相见恨晚,做C++开发要是不知道这些东西,显然不够格。其实每种技术都有他自己的特点,都有他自己的取舍,你如果想使用STL就要按照他的方式来玩,我们平时的主官感觉对STL来说并不一定都适用。什么时候用什么容器,什么时候用什么迭代器,什么时候用什么算法,什么时候不该用循环,这本书都做了解答,可以不夸张的说,这本书看过了才能说自己会用STL了。

当然我们要承认,这个世界是有高人的,如果您能正确的回答我下面的几个问题,那估计您不需要读了。

1.       STL 标准序列容器和关联容器都是什么?有什么区别?非标准的呢?

2.       STL 迭代器有几种都有什么区别?

3.       在什么情况下用什么容器?

4.       什么情况下vector可以比map效率高?

5.       如何写一个自己的内存分配器?

6.       如何调整vector的内存容量,节省内存?

7.       如何修改multiset的键?

8.       如何写仿函数类?

如果您不用上网查就都知道答案,那么恭喜您,您是STL大牛。

如果您懂超过5个,那么同样恭喜您,您至少算个合格的高级工程师。

如果您对超过一半都不知所措,那您也该考虑充充电了。

posted @ 2012-02-10 18:30 SolidMango 阅读(1074) 评论(10) 编辑

2011总结,2012展望,生活技术都不能少

转眼间2012年已悄然来临,春节将至,和大部分的朋友一样,有感于时光飞逝,在这个特别的阶段总想总结一下过去,并展望一下美好的未来,为新的一年做个规划。

总结

身体是革命的本钱,先来说说身体,2011年基本能保证每周打一次羽毛球,一次篮球,每次各两个小时,打完球洗个温水澡,睡个懒觉,这也许就是人生最大的追求了。

外语方面,英语水平稳中有升,单词量也多了一些,本来年初的时候有计划把日语捡起来,后来因为时间不够,没能实施,做个trilingual  的中国牛,不容易啊..

技术方面,主要精力集中在windows开发方面,正如有些兄弟说的,技术这个东西,你每做一次都会有更深入的理解。

2011年重温了《Effective C++》《More Effective C++》《组件对象模型》《COM本质论》对C++的理解和以前的自己比,应该算是更上一层楼了。

.NET 方面通读和挑选了几本中英文的书籍,重点挑选自己以前没注意的和忽略的技术进行研究主要包括:Linq to object, 闭包,协变逆变,以及WCF,其中WCF我只进行了相关的技术学习,写了一些测试的Demo,由于在实际的项目实施中没机会使用,感觉还欠火候,准备有时间继续学习。

调试技术方面,不管实时调试还是事后调试,就非托管代码而言,在什么情况下该用什么样的工具,遇到什么样的问题如何处理可以说已经了然于胸,剩下的只有积累经验,多做多学,其实就是这样,付出越多收获才会越多,不是谁天生就比别人牛很多,都是良性循环的积累的。非托管代码是努力的目标,新的一年准备做一些SOS方面的学习。

基础知识方面,本来年初计划把剩下的一些《算法导论》的内容读完,但是还是没坚持下来,有些算法确实有些晦涩,而且不常用,作为兴趣爱好,时间不够只能往后排,不过也不是完全没有收获,读了一本《数据结构算法与应用C语言描述》,至少常用的数据结构知识又重新温习了一遍。新的一年打算重新研究一些编译原理,重新读一遍龙书,上学的时候是挑着读的,这次打算研读一番..

技术类比和知识扩展方面,2011年出于兴趣和好奇,读了《Learning Python》《JavaScript 高级编程》, 其实工作中这两种技术很少使用,但是经常听见圈里的朋友提起,所以就尝试着学习一下,东西不难,但是值得借鉴的地方还是不少的。

Linux 方面本来计划2011年找个开源的项目跟进一下,一是为开源社区做些贡献,另一方面自己也可以学习一下工作中接触不到的东西,尝试过几次,但是始终没有找到Linux下面规模适合的开源的项目,也可能是小弟没太用心,一直没有找到,如果哪位兄弟了解希望多多指教,在整个2011年,Linux方面只是学习了标准的Make file的写法,Shell, GDB , 进步有限,希望在新的一年里能多花些精力在上面。

Java 代码2011年写的也很少,作为与.net 的类比,他们实在有太多的相似,2011年一年在Java方面的收获仅限于《Java 核心技术》I卷通读一遍,算是温故知新吧。

展望

身体始终是第一位的,2011年的锻炼至少在量上面还是比较成功的,新的一年要再接再厉,锻炼不能只为出点汗,羽毛球和篮球的球技是该提高的时候了,有时间多向高手学习一下,看看相关的视频,请请教练,生活本来可以更美好的, 另外如果时间允许希望可以把游泳学了,这个要真是2012年底就世界末日,小弟还不会游泳呢..

英语方面,希望在词汇,听力,口语方面有所突破,现在虽然和外国友人交流没什么问题,但是总觉得不知道该说些什么好,有待提高啊,如果有时间,日语还是最好学习一下,谁知道哪天日本又出什么NB动画片了,不懂日语就out 了。

技术方面,

C/C++ 不想再读新书了,除非有特别好的,可以打动我,我希望把手里面的C/C++ 方面的书籍和资料整理一些,温故知新,相信量已经到了,希望籍此发生质变。

调试技术方面水还是很深的,非托管代码的调试技术需要加强,做更多的项目时注意积累这方面的经验,相关的技术知识从新整理一遍,托管代码的SOS是自己今年的主要的扩展方向。

.NET 方面,因为这个是工作的主攻方向,准备选择12本书总结一下相关的知识,扫清盲点,特别是内部机理方面的知识。WCF需要大彻大悟啦,估计项目马上就会使用这方面的知识。

基础知识方面《算法导论》需要读完,另外编译原理的英文版龙书需要研读一遍,翻译版的龙书实在不敢恭维。

技术类比和扩展方面如果有感兴趣的东西,希望有时间可以选择12种进行学习。

Linux开发和Java开发希望在今年可以跟进一两个开源的项目。

软件开发的上层建筑设计模式和UML一直在学习,但是感觉还是不能游刃有余,估计是这方面做的想得都不够,所以这方面要努力啊,新的一年希望可以透彻的运用这两项技能,把以前看过的资料和做过的项目都总结一下,尽量画UML,如果可能的话做一下相关的改进。

写了不少,算是给今年画个完整的结束吧.

天行健,君子自强不息,愿大家过个欢乐祥和的春节

posted @ 2012-01-18 16:10 SolidMango 阅读(1422) 评论(10) 编辑

经常发现有人在网上提出这样的问题,现实中也确实有不少人在经历了3-5年的Windows开发之后就开始迷失方向,每天浑浑噩噩混日子,可能是因为这个问题粒度太大,没人愿意花时间回答,希望本文可以抛砖引玉,给大家节省些时间,同时也希望园子里面的兄弟们能尽力的补充,从而使这篇文章可以帮助更多的后来人。

首先说明的是,本文提到的各种技术不分先后,没有顺序,虽然先学什么,再学什么对某些人来说可能更方便,但是这些都不是绝对的,因为每个人的情况不同。

Windows开发首先必须学习的就是操作系统的API,因为其他的一切都是构建于OS之上,所谓九层之台,起于垒土,如果你对linux的系统调用很熟悉就会发现其实他们大同小异,都是应用程序在使用系统提供的功能。

接下来是MFC,有了MFC你才真正的可以干点开发,因为MFC实在是太全了,几乎封装了所有的Windows API, 消息循环,COM实现

到了此地,你可以开始学习调试技术了,熟悉了调试的各种技巧才可以做到事半功倍,得心应手。

接下来是组建对象模型COM,作为windows的基石,不懂COM,很难说自己精通windows编程,因为即使现在的.NET framework也是构建于COM之上,很多问题还是需要SOS到底层去调试。

当你懂得了COM的精髓,你应该开始学习ATL了,这个类库可以使你的COM开发更加得心应手。

说到ATL就不能不提到他的前辈STL,这个出自于标准C++的类库在windows上同样也得到了很好的支持,有了STL在你有一天想转linux开发也同样会用得上。

Windows 8中的WinRT现在还没有应用于实际开发,现有的技术中.NET 是非常值得学习的,因为.NET 的主旨是提高程序员的开发效率,在这个浮躁的世界,开发效率有时候能够代表一切。

COM.NET只有一步之遥,.NET 其实是从COM+演化而来,具体细节请参看 Don Box的《.NET 本质论》了解了这些会使你对.NET的认识上升到一个新的层面。

接下来是C# 因为这家伙是.NET的嫡系部队,除了IL,这家伙可以说和.NET 的关系最为亲近,大部分的新功能都会最先在其中加以体现。当你熟悉了C# BCL,《CLR via C#》可以说这个时候你已经可以胜任基本的C#开发了,可以很快写出一个小工具,完成一个相关的task

接下来是WCFWPF,做分布式开发少不了WCF,同样华丽的界面少不了XAMLWPF

大概罗列了一些,其实每个主题仔细探究下去都很有韵味,还有需要说的是,其实Windows上面好多的东西都和UNIX很像,比如PowerShell明显是为了像UNIX一样,给开发者提供一个更强大的shell, 如果有兴趣,触类旁通一下,也很是有趣。

还有:

LINQ改变了我们的数据操作方式,统一了数据操作模型,经常操作数据的兄弟,你值得拥有。

F#作为一种函数式编程语言也很值得研究,由于本人使用不多,在此不作评价。

另外:

作为基础的算法;

作为提升功力的设计模式,UML

作为改善系统性能的重构;

作为大部分分布式核心的TCP/IP

等等主题也是值得大家研究的。

最后借鲁迅的话收尾:其实地上本没有路,走的人多了也便成了路,希望大家不要把时间都浪费了,原来还有好多东西可以去钻研。

不当之处望大家批评、指正、拍砖, 并提出您的宝贵的意见和补充。

posted @ 2011-11-26 10:45 SolidMango 阅读(3540) 评论(42) 编辑

最近由于项目的关系,对Microsoft在各种编程语言中提供的TreeView控件做了一些研究。最初在网上查了一下,除了MicrosoftMSDN有些分散的knowledge, 并没有发现有这方面主题文章,于是有了写这篇文章的想法,希望可以抛砖引玉,让后来人少走些弯路。

出于个人兴趣的关系,我主要对Microsoft  Visual C++ C#两种语言中的TreeView控件进行了相应的研究,在这两种语言中,对于TreeView控件的基本用法本文不做说明,相对高级的用法主要是为TreeItem设置静态图标和选中图标,drag and drop操作,由于C#中的TreeView控件是所有微软提供的TreeView控件中相对完整,而且设计相对优雅的一个,下面以C#TreeView控件为例就相应的主题分别说明。

先来看看MSDN上给C# TreeView控件的定义:

Displays a hierarchical collection of labeled items, each represented by a TreeNode.

翻译:表现一组有继承结构关系的带有标签的项的集合,每个标签项由TreeNode来表现。也就是说TreeNode表现树的节点,主要工作由它来承担。

那么如何为TreeNode设置图像呢?

如下文字来自MSDN

可以在树节点旁显示图像,方法是将一个 ImageList 分配给 ImageList 属性,然后通过引用 Image ImageList 中的索引值来分配该 Image

使用下面的属性分配图像:

ImageIndex 属性设置为当树节点未选定时所显示的 Image 的索引值。

SelectedImageIndex 属性设置为当树节点被选定时要显示的 Image 的索引值。

ImageIndex SelectedImageIndex 属性值所引用的图像是所有分配给 Nodes 集合的树节点显示的默认图像。 每个树节点都可以通过设置 TreeNode.ImageIndex TreeNode.SelectedImageIndex 属性来取代默认的图像。

看完了这段文字,你知道该如何操作了么?我觉得可能有好多人还是不是完全的理解,那我们就已程序员的语言来描述一下吧:

首先定义一个ImageList变量并将其赋值给TreeViewImageList

1 private System.Windows.Forms.ImageList imageList007;
2 this.imageList007 = new System.Windows.Forms.ImageList(this.components);
3 this.treeView1.ImageList = this.imageList007;

 

然后需要对图标进行设置,

this.imageList007.ImageStream =
((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList007.ImageStream")));
this.imageList007.TransparentColor = System.Drawing.Color.Transparent;
this.imageList007.Images.SetKeyName(0"Icon01.ico");
this.imageList007.Images.SetKeyName(1"Icon02.ico");
this.imageList007.Images.SetKeyName(2"Icon03.ico");
this.imageList007.Images.SetKeyName(3"Icon04.ico");
this.imageList007.Images.SetKeyName(4"Icon05.ico");

 

最后可以对TreeView ImageIndex SelectedImageIndex 属性进行相应的设置,选择相应的图像,也可以对每个动态生成的节点进行独立的图像设置,到此你已经成功的设置了TreeNode的图像。

那又如何实现Drag and Drop 操作呢?

首先我们需要清楚Drag and Drop的源和目标都是什么,也就是说从哪向哪拖拽,每个部分承担的职责是什么,而只有在源和目标上都做了相应的处理,拖拽过程才可能是完整有效的。

源组件处理:

ItemDrag事件: 当鼠标开始对源树节点进行拖拽的时候,会引发这个事件,也就是说这个事件的发出者应该是源组件, 在这个事件处理函数中需要调用DoDragDrop方法 初始化并开始一个拖拽过程。

目标组件处理:

DragEnter事件: 当初始化操作结束以后,我们需要在拖拽目标处处理DragEnter事件,这个事件发生在源节点被拖动到目标组件范围内的某个点的时候,在这个事件中我们可以对这个拖拽的合法性进行验证,并且设置不同的鼠标形状来表示不同的状态,DragDropEffects 结构用于对鼠标形状进行设置。

 

目标组件处理:

DragDrop 事件: 这个事件用于在目标组件中处理拖拽事件,发生于源节点已经被拖拽到目的组件处,这时我们可以对拖拽过来的节点进行解析处理等实际工作。

注意:为了完成拖拽操作源组件和目标组件的AllowDrop都需要设置成true.

 

示例代码,如下代码完成了将一个TreeNode拖拽到一个Form上需要完成的工作:

private void UsingTreeViewDemo_Load(object sender, EventArgs e)
{
   this.treeView1.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeView_ItemDrag);
   this.DragEnter += new System.Windows.Forms.DragEventHandler(this.Form_DragEnter);
   this.DragDrop += new System.Windows.Forms.DragEventHandler(this.Form_DragDrop);
}

private void treeView_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e)
{
    DoDragDrop(e.Item, DragDropEffects.Copy);
}

private void Form_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
    e.Effect = DragDropEffects.Copy;
}

private void Form_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{      
    TreeNode NewNode;
    if (e.Data.GetDataPresent("System.Windows.Forms.TreeNode"false))
    {
          NewNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
          MessageBox.Show(NewNode.ToString());
    }
}

 

至此,本文的使命已经完成,相信大家已经熟悉了这两项相对高级的TreeView用法。欢迎大家就此主题互相讨论,并对本文的不当之处批评指正。

posted @ 2011-11-16 13:52 SolidMango 阅读(1341) 评论(2) 编辑

看到过园子里面几篇协变和逆变的文章,但是总觉得写得不够清晰,文章这东西注重要是要把自己想表达的观点表达出来,这个过程应该是把复杂的东西消化出来从而简单化,清晰化,而不是故弄玄虚,反其道而行之,下面我们言归正传啦。

我们先来看一段MSDN原文给协变,逆变和变体下个定义:

A generic interface or delegate is called variant if its generic parameters are declared covariant or contravariant. Both C# and Visual Basic enable you to create your own variant interfaces and delegates.

如果泛型接口或委托的泛型参数声明为协变或逆变,则将该泛型接口或委托称为变体 C# Visual Basic 都允许您创建自己的变体接口和委托。

通俗解释:

变体定义:带有协变或逆变参数的泛型接口或委托。也就是说协变和逆变主要关注点在泛型接口或委托。

那什么又是协变和逆变呢?

我们先来看下面一个来自MSDN的例子:

 

1 // 协变
2 IEnumerable<string>strings = new List<string>();
3 IEnumerable<object> objects = strings;
 

大家看到了么一个声明为IEnumerable<string> 接口类型被赋给了一个更低 级别的IEnumerable<object>.

对,这就是协变。再来看一个例子:

 

 

class Base

{

    public static void PrintBases(IEnumerable<Base> bases)

    {

        foreach(Base b in bases)

        {

            Console.WriteLine(b);

        }

    }

}

 

class Derived : Base

{

    public static void Main()

    {

        List<Derived> dlist = new List<Derived>();

 

        Derived.PrintBases(dlist);//由于IEnumerable<T>接口是协变的,所以PrintBases(IEnumerable<Base> bases)

                                  //可以接收一个更加具体化的IEnumerable<Derived>作为其参数。

        IEnumerable<Base> bIEnum = dlist;

    }

}

下面给协变下个定义:

协变:让一个带有协变参数的泛型接口(或委托)可以接收类型更加精细化,具体化的泛型接口(或委托)作为参数,可以看成OO中多态的一个延伸。

 

// 逆变
// Assume that the following method is in the class: 
// static void SetObject(object o) { } 
Action<object> actObject = SetObject;
Action<string> actString = actObject; 
//委托actString中以后要使用更加精细化的类型string不能再使用object啦!
string strHello(“Hello”); 
actString(strHello);

 

大家看到了么?一个声明为Action<object>的类型被赋给了一个Action<string>,大家都知道,Action<T>接收参数,没有返回值,所以其中的objectstring是其参数,这个过程其实就是参数的约束更加强了,也就是说让参数类型更加精细化。下面我们来给逆变下个定义:

逆变:让一个带有协变参数的泛型接口(或委托)可以接收粒度更粗的泛型接口或委托作为参数,这个过程实际上是参数类型更加精细化的过程。

 

一句话总结:协变让一个粗粒度接口(或委托)可以接收一个更加具体的接口(或委托)作为参数(或返回值);逆变让一个接口(或委托)的参数类型(或返回值)类型更加具体化,也就是参数类型更强,更明确。

通常,协变类型参数可用作委托的返回类型,而逆变类型参数可用作参数类型。 对于接口,协变类型参数可用作接口的方法的返回类型,而逆变类型参数可用作接口的方法的参数类型。

 

 

 

posted @ 2011-11-09 13:32 SolidMango 阅读(3447) 评论(28) 编辑
摘要: 1.0--3.5sp1http://msdn.microsoft.com/zh-cn/library/ms171868(v=VS.90).aspx4.0http://msdn.microsoft.com/zh-cn/library/ms171868(v=VS.100).aspx阅读全文
posted @ 2011-10-11 19:20 SolidMango 阅读(67) 评论(0) 编辑
摘要: C# 语言规范没有定义编码标准。 但是,Microsoft 使用本主题中的这些指南开发示例和文档。 编码约定可实现以下目的:它们创建一致的代码外观,从而使读者可以关注内容而非布局。它们使读者能够根据以前的经验作出假设,从而更加快速地理解代码。有利于复制、更改和维护代码。演示 C# 最佳做法。命名约定 命名指南在 名称准则 中介绍。 您无需更改由 Visual Studio 设计器工具创建的对象的名称,就可以让它们符合指南。 在不包括 using 语句 的简短示例中,使用命名空间限定。 如果您知道默认情况下会将某命名空间导入项目中,则无需完全限定来自该命名空间的名称。 如果限定名称太长无法放入一阅读全文
posted @ 2011-10-10 21:15 SolidMango 阅读(38) 评论(0) 编辑
摘要: 1. Handle Leak:A handle leak is a type of software bug that occurs when a computer program asks for a handle to a resource but does not free the handle when it is no longer used. If this occurs frequently or repeatedly over an extended period of time, a large number of handles may be marked in-use .阅读全文
posted @ 2011-10-10 20:35 SolidMango 阅读(165) 评论(0) 编辑
摘要: 计算机排序算法主要分为内排序和外排序,内排序主要指数据存储在内存中的排序,外排序通常指待排序的数据量很大,而且大部分数据存储于文件中,排序时需要读写文件的排序。通常大家讨论的都是内排序,因为内排序是外排序的根基,通常外排序过程都程序要辅助内排序。 最常见的内排序是冒泡排序,其时间复杂度为O(n^2), 空间复杂度为O(1),基本上属于就地排序,而且该算法具有稳定性,在数据量不大,而且顺序基本已经排列好的情况下,该算法应该被优先考虑,其实现代码如下:冒泡排序(Bubble Sort)//DataswopfunctionvoidSwap(int&p,int&q){p=p^q;q=p阅读全文
posted @ 2011-06-20 17:33 SolidMango 阅读(882) 评论(0) 编辑
摘要: 1. Domain Login 验证用户权限publicboolValidateDomainUser(stringUserName,stringPassword,stringDomain){boolbValid=false;using(PrincipalContextcontext=newPrincipalContext(ContextType.Domain,Domain)){bValid=context.ValidateCredentials(UserName,Password);}returnbValid;}2. Domain Mode读取privatevoidDomainModeChec阅读全文
posted @ 2011-04-22 14:23 SolidMango 阅读(932) 评论(0) 编辑