向左右向右走 —— 小时了了的技术博客

关注C++开发技术、架构设计、软件项目管理、软件产品管理等

摘要: 自 VS2010 起,微软就在 CRT 中集成了并发运行时(Concurrency Runtime),并行模式库(PPL,Parallel Patterns Library)是其中的一个重要组成部分。7 年过去了,似乎大家都不怎么Care这个事情,相关文章少少且多是蜻蜓点水。实际上这个库的设计相当精 阅读全文
posted @ 2017-06-17 10:14 小时了了 阅读(1839) 评论(0) 推荐(1) 编辑
摘要: 有两个 API 可以实现保存 GUID 到 VARIANT InitVariantFromGUIDAsBuffer 以字节数组形式保存,保存类型为 VT_ARRAY | VT_UI1,相当于字节拷贝,理论上效率更高; InitVariantFromGUIDAsString 以字符串形式保存,保存类型 阅读全文
posted @ 2017-02-21 20:41 小时了了 阅读(227) 评论(0) 推荐(0) 编辑
摘要: 这两天写的代码概率性的崩溃在 XMMatrixMultiply() 函数,XMMatrixMultiply() 本身是 inline 函数可以看到崩溃处的代码: vX = _mm_mul_ps(vX,M2.r[0]); 经查,_mm_mul_ps 是 SSE2 指令要求内存地址 16 字节对齐。猜想 阅读全文
posted @ 2016-03-06 14:35 小时了了 阅读(1166) 评论(1) 推荐(1) 编辑
摘要: WRL::ComPtr 取原始指针的地址有两种方式: 显然,operator& 是为COM风格的API设计的,比如下面这种: 在这一点上和 ATL::CComPtr 一致,实现上则有不同。上面这种 API 最容易出现的错误是传了一个非空指针的地址给 ppObj ,然后指针被覆盖导致原来指向的对象无法 阅读全文
posted @ 2016-03-05 23:28 小时了了 阅读(1805) 评论(1) 推荐(1) 编辑
摘要: IStream 和IRandomAccessStream^ 互转 IRandomAccessStream^ -->IStream:CreateStreamOverRandomAccessStream IStream -->IRandomAccessStream^: CreateRandomAcc... 阅读全文
posted @ 2015-10-18 12:04 小时了了 阅读(726) 评论(9) 推荐(1) 编辑
摘要: StorageFile.ContentType 属性,是 string 类型,用来表示文件内容的 MIME 类型。例如,音乐文件可能有 "audio/mpeg" MIME 类型。(MSDN)MIME 类型的定义可以下面的链接找到:MIME Types -http://blogs.msdn.com/b... 阅读全文
posted @ 2015-10-10 19:16 小时了了 阅读(490) 评论(2) 推荐(1) 编辑
摘要: 在UWP中加载文件一般先创建StorageFile 对象,然后调用StorageFile.OpenReadAsync 方法得到一个IRandomAccessStream 接口用来读取数据:1 StorageFile image_file = await StorageFile.GetFileFrom... 阅读全文
posted @ 2015-10-04 17:35 小时了了 阅读(1086) 评论(0) 推荐(0) 编辑
摘要: 纤程(Fiber)和协程(coroutine)是差不多的概念,也叫做用户级线程或者轻线程之类的。Windows系统提供了一组API用户创建和使用纤程,本文中的库就是基于这组API实现的。纤程的概念中有两个关键点: 纤程拥有独立的栈空间和寄存器环境; 纤程在用户态实现调调度,也就是说完全由程序员控制; 阅读全文
posted @ 2014-12-21 21:32 小时了了 阅读(5092) 评论(0) 推荐(2) 编辑
摘要: 提到输入输出流,作为CPPer很自然的就会想到std::iostream,对于文本流的处理,iostream可以说足够强大,应付一般复杂度的需求毫无压力。对二进制流处理却只能用“简陋”来形容,悲催的是,作为一个在多媒体软件领域默默耕耘多年的码农日常打交道最多的偏偏就是二进制流。前些年流行过一本书叫做... 阅读全文
posted @ 2014-08-06 23:15 小时了了 阅读(2147) 评论(1) 推荐(1) 编辑
摘要: StretchBlt:从源矩形中复制一个位图到目标矩形,必要时按目标设备设置的模式进行图像的拉伸或压缩,如果目标设备是窗口DC,则意味着在窗口绘制位图,大致的使用代码如下: 1 void DrawImage(HDC hdc, HBITMAP hbm, const RECT target_rect) 2 { 3 HDC hdcMemory = ::CreateCompatibleDC(hdc); 4 HBITMAP old_bmp = (HBITMAP)::SelectObject(hdcMemory, hbm); 5 6 BITMAP bm = { 0 }; 7 ... 阅读全文
posted @ 2014-04-05 13:53 小时了了 阅读(4009) 评论(0) 推荐(1) 编辑
摘要: 任何产品的用户群体都可以划分为高端和低端。对产品有深入学习研究能熟练应用的是高端用户,不擅长技术只做一些简单应用的是低端用户。这里的高端低端是从“使用产品”的角度来看待的,不同的角度会带来不同的划分方式,比如按用户的参与程度划分成活跃用户和非活跃用户,一个用户可能是高端的活跃用户,也可能是高端的非活跃用户。这里要强调的是下面几个观点:第一,高低端的划分是针对特定产品的,在一类产品中属于高端的用户在另一类产品中可能属于低端用户。这很容易理解,比如我可算是Visual Studio的高端用户,但对Photoshop我就是绝对的低端用户。第二,用户是不断成长的,有一个从低端到高端的过程。开始用一个产 阅读全文
posted @ 2011-11-19 11:00 小时了了 阅读(565) 评论(0) 推荐(0) 编辑
摘要: 经常看到有人问程序员适合做管理吗,或者手底下有牛人比我技术更好怎么办,或者感叹一下做管理好难啊之类的。同时,相当大的一部分程序员都梦想着走所谓专家路线——并不是因为对技术特别有兴趣或者觉得自己特别适合走技术路线,真正的原因是对管理工作的恐惧,觉得自己搞不定定。做管理真的很难吗,程序员出身到底适不适合做管理,我可以斩钉截铁的告诉你:不难!适合!上面的答案显然并不完全正确。不过我们今天我们讨论的并不是管理一个国家那样的管理,也不是管理一个公司或者半个公司这样的管理——绝大部分程序员同志们短时间内都不会有这样的机会,这样的话题也完全超出了我的知识范畴。我们今天讨论的只是基础的简单的管理,小到几个人的 阅读全文
posted @ 2011-11-15 00:05 小时了了 阅读(287) 评论(1) 推荐(0) 编辑
摘要: 前几天为了查找一个BUG花了几乎一整天的时间,然后——就像江湖传说的一样,只改了一行代码就搞定了。至于原因仅仅是因为一个变量未初始化,一秒钟的疏忽却花了一天的代价来弥补,就像那个蚂蚁和大象的段子:风流了一夜,挖一辈子的坑。 这类BUG通常是不稳定重现的测试未必测的出来,测出来了也未必容易定位,若是不小心留到了用户那里可能真的就成了一辈子的坑,永远都解决不掉了。这样的事我想命苦的C++程序员们初入江湖的时候可能都遇到过那么一两回。——声明一下,以前我也搞出过这样的BUG,但从那之后没再犯第二次错误,这次的代码是别人写的。 俗话说人是靠不住的,只有靠制度才有保障,哪怕我们再小心也总有马虎大... 阅读全文
posted @ 2011-11-11 00:38 小时了了 阅读(2120) 评论(9) 推荐(3) 编辑
摘要: 前几天博客园编辑推荐了一篇文章《“品质在于构建过程”吗?》,对决定软件品质的核心要素进行了许多探讨。我今天想讨论的也是这个话题。 “品质在于构建过程”并不是什么惊骇世俗的新观点,实际上类似的说法由来已久,比如“过程决定质量”,“品质在于构建过程”只是有软件行业特色的另一种表达形式而已。那么“过程决定质量”的说法是哪来的呢?答案是工业工程,如果你从事过工业制造行业,比如汽车制造、手机制造之类的,几乎不可能没听说过这句话。首先我们辨析一下工业工程和软件工程这两个概念,下面是来自百度百科的定义:工业工程(Industrial Engineering 简称IE),是从科学管理的基础上发展起来的一... 阅读全文
posted @ 2011-11-05 22:10 小时了了 阅读(1494) 评论(6) 推荐(2) 编辑
摘要: 事情缘起于代码走读会议的一次讨论。基本的需求很简单,就是实现类似下面这样一个函数:HRESULT GetText(/* [out] */BSTR* pText); 很自然地,首先写出来的实现是这样的:HRESULT GetText(/* [out] */BSTR* pText){ ASSERT(pText != NULL); *pText = ::SysAllocString(L"This is the text."); return S_OK;} 它的调用方式如下(这里为了简单起见我们忽略掉了对返回值的判断): BSTR bstText = NULL; GetText(& 阅读全文
posted @ 2011-10-30 11:55 小时了了 阅读(1316) 评论(5) 推荐(5) 编辑
摘要: 有一种普遍的说法是把封装、继承和多态并称为面向对象的三大特征。如果你很熟悉C++并且对面向对象思想有过一些思考,那么很可能对这个说法有过怀疑,面向对象思想在本质上认为世界是由对象构成的,和面向过程是世界观的不同,而所谓的三大特征实际和面向对象的思想本质没有半毛钱的关系,准确的表述应该是封装、继承和多态是C++相对于C的三大特征。如果你碰巧了解一点C++编译器可能会发现封装也好,继承、多态也好都只是语法糖,技巧层面的东西而已,和思想无关。以上为废话。本文主要就C++的继承机制进行一些讨论。很多C++教材在讲到继承时喜欢利用几何上的一些概念,比如对如下的集合关系进行建模: 在一次内部技术培训的时候 阅读全文
posted @ 2011-10-17 09:08 小时了了 阅读(1838) 评论(17) 推荐(3) 编辑
摘要: 需求源于为博客文章添加tag的字符串处理: tag之间以“,”分隔,要根据这个分隔符分离出各个tag;另外处于习惯用户可能敲入多余的空格,所以需要对tag的左右空格进行剪切。STL的string类没有现成的方法只好自己写一个。第一版函数原型如下:Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->void find_all_words(conststring& str, char decollator, vector words);其中参 阅读全文
posted @ 2011-01-22 15:56 小时了了 阅读(751) 评论(0) 推荐(1) 编辑
摘要: 我们假设这样一种应用场景,有两个类A和B,在B中需要调用A的一个方法(成员函数)。那么我们的代码可能是这个样子的:class A{public: void Func(void) { printf("%s\r\n", __FUNCTION__); }};class B{public: void UseA() { a->Func(); }public: A* a;}; 调用代码是这样的:A a;B b;b.a = &a;b.UseA(); 我们观察上面的代码,看看有什么问题:两个类中B对A产生了一个依赖关系,这让人有点不爽;哪天我们想用另外一个类C替代A的作用意味 阅读全文
posted @ 2010-12-06 12:22 小时了了 阅读(534) 评论(3) 推荐(2) 编辑
摘要: 先看一段使用了std::list的代码: std::list array; for(int i = 0; i ::iterator it = array.begin(); it != array.end(); ++it) { (*it) += 1; } for (std::list::iterator it = array.begin(); it != array.end(); ++it) { printf("%d\t", *it); } 我们观察这段代码。首先,它是正确的,没什么错误,但看起来太臃肿了。本来我要完成每个元素的值加1关键的代码只有一行 (*it) += 1; 阅读全文
posted @ 2010-12-04 15:49 小时了了 阅读(1262) 评论(0) 推荐(0) 编辑