posts - 16,  comments - 34,  trackbacks - 0
共10页: 1 2 3 4 5 6 7 8 9 Last 
re: loki技法(1).静态断言 OwnWaterloo 2010-04-01 22:57
为了让编译器输出的错误信息更容易理解一些:
LOKI_STATIC_CHECK(sizeof(char)==1, bad_compiler );

如果断言失败, 输出的就是:
ERROR_bad_compiler 是一个不完全类型的object。
re: 将成员函数作为回调函数 OwnWaterloo 2010-04-01 18:31
@Sanxcoo
gcc下有继承关系。
msvc下有多继承关系。

指向成员的指针就可能不仅仅是一个地址。
re: 将成员函数作为回调函数 OwnWaterloo 2010-04-01 17:41
注意, 成员指针并不一定仅仅是地址。
所以最安全的作法是实现一个转发函数, 而不是去取地址:

void forwarding(void* o, int i, double d)
{
static_cast<C*>(o)->F(i, d);

}

然后将forwarding绑定到一个object上:
C o;
void (*f)(int, double ) = bind(forwarding, &o);

然后将f传递给需要回调的地方:
f(1212, 3.26);

等效于:
o.f(1212, 326);
re: 将成员函数作为回调函数 OwnWaterloo 2010-04-01 17:36
取成员指针地址:

template<typename D,typename S>
D cast_union(S src)
{
union
{
S src;
D dst;
} u = {src};
return u.dst;
}

uintptr_t address = cast_union<uintptr_t>(&C::F);
@陈梓瀚(vczh)
>> 一大堆lib搞定了,你挑一个正确的就好了。
挑得出来吗?

你会为VC6用户生成相应的binary吗?

客户使用了-fabi-version 怎么办?
客户使用了-mno-align-double又怎么办?

你要规定用户所使用的编译参数? 你能规定用户使用的编译参数?
你能确保用户"仅仅使用你一个人的库"?

你想得太简单了。

>> 那么肯定会有些约束的
这些约束会被很不经意的打破。 很难控制住。
因为C++给了程序员太多可以玩, 可以炫的东西。
所谓的"心智包袱"。

>>尺寸特别小,static没有任何坏处
算了, 你总是把很有争议的话说得如此绝对, 我还能说你什么呢。


而且我第3次强调了, 我不想讨论全局初始化失败应该怎样。
你觉得应该怎样你可以继续说。

我上面举的例子, 仅仅是为了说明对"全局的依赖很难避免"。
我觉得已经足够说明了。
@溪流
如果由使用MIT许可证的代码衍生:
只要在源代码中保留原MIT声明即可。

如果由使用BSD许可证(3条款版本)的代码衍生:
1. 源代码形式发布
同MIT
2. 二进制形式发布
发布的同时附带衍生自的代码中包含的BSD声明。

3. 无论以什么形式发布, 原声明中出现的人名、组织名、公司名不得用于其他用途。
MIT不是保留源代码中的MIT就可以了么?
@陈梓瀚(vczh)
>>显然“所有流行编译器版本”是一个你只需要下载完写了从vcproj到的makefile生成器以后就自动完成的事情,一劳永逸也,想做当然能做,而且随时更新。

这只是构建脚本而已。 我说的是不同编译器产生出的二进制代码的兼容性。
你能用msvc链接到一个mingw生成的二进制库吗?
你能用msvc链接到前一个crt版本吗?

>>运行库版本一律使用static链接,因此可以跟你的编译器版本捆绑在一起。
看吧, 你又"一律", "一定" 什么的了。

这是C++语言本身的问题。 C++的特性太复杂, 而且是一门开放的语言, 所以会有很多二进制上不兼容的特性。
而且C++这门语言本身就会促使开发者使用复杂的设计。

>> 一个程序不可能也不应该同时使用N套平行的GUI库(嵌套关系除外)
你没见过而已。 确实有这样的东西存在。 MFC+WTL+还有一个什么忘记了。
当然, 那东西确实丑陋。
不过已经是这样子了, 推倒重来的代价公司受不起, 用户也受不起。


>>main之前的任何异常都不要捕捉,任由崩溃。想log就捕捉了log,log完还是要throw;以便崩溃
再次强调, "需要全局的依赖" 和 "处理全局初始化错误" 是两回事。
@溪流
这样很好。 不要闷头只顾写代码; 花一些时间思考。
>>我需要给 vector(size_t size) 标记上 throw 吗?如果不标记,使用者怎么知道这里可能会有异常?

不需要, 不标记就是throw all。

new失败了
1 :让bad_alloc直接向上抛就是了
为什么不需要大量的try catch?
因为向上抛的过程中会析构栈上的对象, 回滚状态, 并找到一个处理器。
你会将代码写成异常安全的, 是吧?

2: 采用两段式。
其实就是使用返回状态代码的处理方式了。

在某个函数f中, 先构造一个半成品, 在使用之前create或者怎样。
如果失败, 就通过状态码向f的调用者报告。
f的调用者g又可能向g的调用者继续报告。
直到找到一个能处理的地方。

这其实和异常是相同的, 只是异常对这些过程是自动的。
最近很活跃嘛
@陈梓瀚(vczh)
>>初始化的时候连内存都申请不了应该直接崩溃,这是最好的办法。所以这个不是理由。

"申请不了"同"需要依赖内存分配器已初始化" 完全是两码事。
你又跑题了。

>>任何库不应该悄悄启动线程,除了GUI

这只是"你觉得"应该这样。
但你马上又说了一个反例。

3. 我只想说对全局某些服务的依赖是很难避免的。
singleton关我什么事? 我老早不用这种脱了裤子放屁的玩意了。


>>作为一个库的发行者,要么提供C++代码,要么提供所有流行编译器的二进制编译结果。这才是负责任的。

作为一个二进制库的发布者, 将库用C实现并提供C++的header-only的绑定层; 或者发布C++的源代码。
这才是负责任的。

所有流行编译器? 你知道什么叫所有流行编译器么?
编译器种类×编译器版本×编译器运行库版本×你的库版本

你觉得你能负这个责, 你就继续玩吧。
@溪流
是Loki啦:
http://en.wikipedia.org/wiki/Loki_(C%2B%2B)
http://loki-lib.sourceforge.net/

配套的《modern c++ design》是目前看过的最高级的C++书……

boost也有scope_exit,是重量级的。
Loki的ScopeGuard依赖"现有的函数", 比如CloseHandle。
注册之后, 在block退出时, 会调用这个函数。

而boost scope_exit是"就地编写退出代码"(调用函数也包括在内)。
当退出时, 会执行这些代码。
@溪流
不是给你说了有范型的RAII(RRID)类吗?
 
int f()
{
      HANDLE process 
= OpenProcess(  );
      
if (!process)
            
return 0;
      LOKI_ON_BLOCK_EXIT(process, CloseHandle);

      HANDLE token 
= OpenProcessTokon(  );
      
if (!token)
            
return 0;
      LOKI_ON_BLOCK_EXIT(token, CloseHandle);

      
if ( !LookupPrivilegeValue(  ) )
            
return 0;

      
if ( !AdjustTokenPrivileges(  ) )
            
return 0;

      
return 1;
}

cppblog插入代码很繁琐……
你看是这样吗?
int f(void)
{
      HANDLE process 
= 0;
      HANDLE token   
= 0;
      
int r = 0;

      
do {

            
if ( process = OpenProcess(), !process)
                  
break;
            
if ( token = OpenProcessToken(), !token )
                  
break;
            
if ( !LookupPrivilegeValue( ) )
                  
break;
            
if ( !AdjustTokenPrivileges( ) )
                  
break;

            r 
= 1;

      }
 while (0)


      
if ( token != N(OpenProcessToken) ) CloseHandle(token);
      
if ( process!= N(OpenProcess) ) CloseHandle(process);
      
return r;
}

@陈梓瀚(vczh)
>>话说回来,只要保持singleton必须在main前构造完毕这个原则的话,就算你singleton的创建互相依赖,也是不需要锁的。

class evil
{
evil()
{
pthread_create(... );
_beginthreadex( ... );
}
};

如果这个例子确实太邪恶, 别忘了还有可能会碰见进程共享数据。
@陈梓瀚(vczh)
>>不管要不要代码初始化,只要你坚持所有不同的singleton对象都不需要依赖于其他singleton对象来创建那么就没有问题。如果不行,那么证明设计有错,或者没错但是很难实现,或者没错很容易实现但是很容易写出bug,总之要改。

你说得也太武断了。 设计有问题?
总有东西的初始化需要申请内存, 能不依赖C heap和C++ free store?

初始化后有部分东西又需要向atexit注册, 又依赖另一个全局的东西。
初始化失败, 有部分人喜欢写log(虽然我不喜欢), 再次依赖全局的东西。
@陈梓瀚(vczh)
>>用一种语言去表达一些概念,如果造成不可消除的重复代码或模式的话,那么应该在可能的情况下更换语言。

只所以要说C:
1. 上面提到了C
2. C++做二进制兼容的东西很烦

而且, 如果不了解C++在初始化静态对象时做了哪些工作, 就会犯错。
比如, 很多人都觉得C++静态对象初始化是线程安全的, 其实是和实现相关的。
大哥, C++有析构函数, 根本不会写出这种代码。
而且, 也不需要一个handle一个RAII类, 有范型的Loki::ScopeGuard, 有boost::scope_exit, 爱怎么玩就怎么玩。

C语言, do while(0) 一层就够了。
注意利用不可能的handle值。
@陈梓瀚(vczh)
main之前自动初始化也是需要代码的。

C++的运行库会帮忙做这个事情。而C不行。 至少标准C不行。
编译器提供的DllMain或者 __atrribute__(constructor)啥啥的不算。

所以, C里面init是需要的。
@空明流转
>>都一定是GetXXX()这样一个自由函数的实现

这没错。 而且还要区分2种语意:
1.
xxx_init
...
xxx_get

2.
xxx_get_and_init
第2种语意我不喜欢。


将xxx_get, xxx_init搞成xxx::instance完全是脱了裤子放屁。
本身就是一个free function的事情, 非要搞出个class出来。
@volnet
现在不也这样么? 如果是按C语法编译的话。
有办法按C99语法编译么?
C89中声明必须在block的头部, 然后是语句。
C++中声明也是一个语句, 所以就没有这个区别了。


另外, 问问lz:
>>在未开启编译器选项为标准C99的情况下,是会编译出错的。
msvc怎么开启标准C99? msvc好像是不支持c99的?
re: vim ctags taglist 入门应用 OwnWaterloo 2010-02-22 00:50
应该是gnumake, 所以搜索规则是GNUMakefile, Makefile, makefile(排名不分先后,因为我不知道……)
make -f filename 啦
其实*nix的软件学习还是容易, --help便是, 就是不常用就记不住-_-

omnicppcomplete 据说很强大, 不过没用过。
感觉类似va那种"一边输入一边就会出现某些提示"不太符合vim的insert模式的风格……

ubuntu默认没有装vim?


赶紧去学autotools那套东西啦, 还有pkg-config。
你要发布*nix下的软件,用户不会关心你编写代码的编辑器,而是会关心编译代码和管理依赖的脚本……

然后写点心得出来, 偶坐享其成~
re: Placement new的用法及用途 OwnWaterloo 2010-02-20 16:15
标准使用方法, 在第1步中应该只涉及内存分配行为, 比如使用operator new, operator new[], malloc。
memset也是不必要的。
在第5步中, 应该只涉及内存归还行为, 比如使用operator delete, operator delete[], free。
@Kevin Lynx
编译器根据什么规则来判断某个没有被使用的符号可以不必链接到binary中?
这个规则我不了解, 可能C++标准有描述, 也可能没有。

我只是猜想 :
1. 如果某个extern符号没有被链接到binary中, 那将其改为static, 应该也不会被链接到binary中。
2. 如果某个static符号没有被链接到binary中, 那将其改为extern, 也许就会被链接到binary中。

这就是机会的意思。

btw, 改为extern const 有效么?
@Kevin Lynx
在C++中, 非local的const对象, 默认是staic链接……

a.cpp
int g_i;

虽然g_i也不一定能被添加到最终代码中, 但机会应该比:

a.cpp
static int g_i; 要大。
@abilitytao
不知道了…… 要有错, 也应该是uint32_t 没有定义才对……

float toIEEE754(unsigned x)
{

typedef int constraint[sizeof(unsigned)==sizeof(float)? 1:-1];

union {
unsigned src;
float dst;
} u = x;

return u.dst;

}
试试在product_a.cpp中, 将:
const bool _local = factory::instance().register( PRODUCT_A_TYPE,...
改为:
extern const bool local_ = factory::instance()...
或者:
namespace {
extern const bool local = ...
}

可能有效,可能无效。


即使有效,依然不能保证local的初始化顺序。main之后执行的代码,可以保证所有产品已经被注册,main之前没有保证。
@abilitytao
这个…… 不就是普通的C函数么?

uint32_t x = 0;
float f = 0.0f;
sscanf("420B999A", "%x", &x );
f = toIEEE754(x);
printf("%.1f", f);
34.9
只要知道处理器使用的是IEEE754, 比如i386, 直接:

float toIEEE754(uint32_t x)
{

union {
uint32_t src;
float dst;
} u = x;
return u.dst;

}

即可。



顺便说说…… 题目出得很垃圾…… 语言都不通顺……
傻了吧唧的……
1. 在C/C++代码正确且C/C++实现(编译器,运行库)正确的情况下, C/C++语言保证得到正确的结果。

如果出现了错误的结果, 可以问why。
是"C/C++代码正确"这个假设有误? 还是"C/C++实现正确"这个假设有误?


2. 如果C/C++代码本身有某种错误, C/C++实现不保证得到正确的结果, 也不保证得到错误的结果, 更不保证会报告错误的结果。
代码的错误有可能会被隐藏, 到其他时候发作。

这时候, 询问"为什么没有出现错误", 是不明智的。
C/C++实现没有义务保证产生一个错误。
@mikecheng
你很悲剧,你仔细阅读的manual中的那个例子是错的。
re: 与临时对象的斗争(下) OwnWaterloo 2009-12-04 00:22
哦…… 原来这种技术叫expression template……

其实我心里一直这么叫它的:operation proxy……
re: 与临时对象的斗争(上) OwnWaterloo 2009-12-03 16:40
@空明流转
上面好像没说清楚…… 我整理一下……

1. 开发的软件使用商业许可证。
发布的binary使用的是,比如mingw,生成的。
也发布源代码。
但发布前使用VC express作移植性测试。
当然,还包括VC使用的工程文件也会发布。
有VC授权的人,可以自己使用VC编译。

这样算侵权么?

2. 开发的软件使用非商业许可证,比如new BSD或LGPL
发布源代码,VC工程文件。侵权么?
发布VC编译的binary呢?

re: 与临时对象的斗争(上) OwnWaterloo 2009-12-03 16:33
@空明流转
嗯,谢谢~


如果我只是想用VC的编译器测试一下可移植性。
但并不发布VC生成的binary。
这样可以么?


或者,我开发的东西使用的是new BSD或者LGPL之类的许可证,可以使用VC express么?

re: 与临时对象的斗争(上) OwnWaterloo 2009-12-03 00:27
@唐风
机器上的vs2005和2008是学校给的…… 据说有个什么政策,学校每年只用付3000元就可以使用大量的正版软件。
不过…… 我已经毕业了…… 机器上的还没删…… 继续用着……
还去下了一个vc10精简版…… 这肯定是D版了……

据说vc9有免费的,不含ide。

re: 与临时对象的斗争(上) OwnWaterloo 2009-12-02 23:51
@唐风
DB是什么???

对那些保守党,就任由他们去吧……
让他们在自己的世界里自娱自乐,一次又一次的发明那属于自己心中完美轮子。
都复用别人的,他们还怎么好开口向老板要钱啊?
一定要说:stl对我们的项目都是不适合的! —— 以显得自己的项目很牛逼。
然后追加:所以我们自行开发了xxx! —— 以显得自己很牛逼。


re: 与临时对象的斗争(上) OwnWaterloo 2009-12-02 22:58
lambda,aotu,decltype这些都是很有用的特性,没它们有时候真的是相当的不方便……

而且,lambda完全可以很简单的纯手工模拟一个。
这种毫无新意的机械复制的事情,本来就应该交给编译器去做。
编译器实现lambda表达式是不需要花什么力气的。
只是解析可能会出现麻烦……

auto、decltype更是容易。
其实编译器已经实现了它们,只是没有暴露出来而已。

期待c++0x流行啊……

re: 与临时对象的斗争(上) OwnWaterloo 2009-12-02 22:50
gcc新版本也支持了。 gcc4.4.0 的stl已经加上对move的支持了。

没有右值引用,也可以消除很多临时变量,只是编程很复杂……
需要使用一些proxy,用来"记录""操作与操作数",仅仅是"记录"。
只有当出现操作的"接收者"时,操作才被真正执行,直接在接收者上进行操作了。

当然,有move更好,本来就应该是这样,对立马就要消亡的对象,盗取一些资源是很合理的……
只是不知道c++0x要什么时候才能流行起来……

看看现在还有N多用vc6的人…… 无语……


re: 散列3 OwnWaterloo 2009-11-27 23:52
http://download.csdn.net/source/747860

扫描版的,凑合着看吧……
源代码在这里:
http://code.google.com/p/cii/downloads/list

re: 散列3 OwnWaterloo 2009-11-27 23:50
@小罗罗
这…… 那链接上不是说已经绝版了吗?
re: 散列3 OwnWaterloo 2009-11-27 20:56
@小罗罗
只看源码很枯燥,而且有些细节很难理解。
看这本书吧:《C语言接口与实现:创建可重用软件的技术》
http://www.china-pub.com/14974

里面的arena,思想和CvMemStorage是一样的"零取整放"。
CvMemStorage比arena多一些功能。

书里将arena的同时,会把内存分配器的一些细节说清楚,这些可能是看源代码多遍都看不出来的。
反正arena章节也不多……

re: 散列3 OwnWaterloo 2009-11-27 18:34
研究opencv的内存管理? 如果是为了使用opencv,可以去研究。

如果是为了研究内存管理…… opencv的内存管理其实很磋……
当然,opencv可能只是为了开发一个足够库自身使用的内存管理与动态数据结构而已。就这个需求来说,opencv是达到了。


但"足够库自身使用"不一定就能满足用户的所有需求。
而opencv也不提供任何方法让用户扩展它的库。
从这方面来说,opencv是相当的鼠目寸光。


比如opencv提供的CvCapture。其内部是有一个C实现的capture接口与capture工厂。
可是它不将接口定义暴露给用户。
用户需要自己的capture时怎么办? 等着opencv去支持吗? 那是不可能的。只能自己动手。
这个需求还好, 大不了让自己的capture返回image(image or matrix),然后丢给opencv去处理就可以了。
image的格式opencv还算厚道,暴露出来了。
用户如果想要实现得好一些,更capture无关,就需要自己再抽象一个capture接口,然后将opencv的capture包含进去 —— 基本就是将CvCapture的代码再实现一遍 —— 因为那短视的opencv没将这个可扩展点暴露出来。



如果用户不满意CvMemStorage和CvSeq的行为,哼哼……
必须屈服,除非用户想自己重写opencv —— 换句话说,就是放弃opencv。

CvMemStorage实现的是一个"多次取、整体放"的策略。
所有的动态数据结构都将数据存放在CvMemStorage分配的内存上。
没有单独释放数据结构中某个元素的方式,只能释放整个Storage。
可是opencv没有定义出一个接口,作为CvMemStorage和CvSeq之间的中间层,而是CvSeq直接使用CvMemStorage。

CvMemStorage本身也不咋嘀。甚至还有一个单次分配大小的上限……

一句话,opencv需要输出动态数据结构的算法和CvSeq绑死了,CvSeq又和CvMemStorage绑死了,而CvMemStorage又实现得不咋嘀……
你要使用opencv吗?请忍受CvMemStorage……
相比CvCapture可以绕过去;这个问题几乎无解。

re: 随笔:对象思想 VS. 过程思想 OwnWaterloo 2009-11-27 17:37
感觉…… 有点文不对题……
文中的重点在于一个函数应该只完成一件事情。
这"一件事情"如何定义…… 可能把它说成"一个需求"更恰当。

一个函数应该只实现一个需求,这个需求一个整体的,要么不变,要么整体改变,不会只变一部分。
目的还是在于能更好的应对需求变化。


这跟"过程" vs "对象"没什么关系吧?

re: 函数调用栈初探 OwnWaterloo 2009-11-27 02:29
你本来写的是【quote】吧? cnblogs确实很偏心,cppblog确实是穿小鞋的……

说正题……
这里的评论里可能有你感兴趣的内容:
http://www.cnblogs.com/JeffreyZhao/archive/2009/11/17/linker-loader-library-correction-about-call-stack.html#1704232

关于push ebp,frame pointer,call-stack,debugging等。

有点长哦,一直往下看。
哈哈,评论的主角就是这篇文章中提到的RednaxelaFX。
应该是同一个人吧?
re: Void and void pointer OwnWaterloo 2009-11-25 01:11
@zml_cnnk
不知道你具体代码是怎样的。

我猜可能是这样。 一个调用链上
1. 一开始是有类型的
2. 到了某个地方,使用了void*去保存任意类型,原来的类型就丢失了。
3. 需要析构,找不到类型了。

要想办法把类型信息带着。


举个标准库中的例子, 保存指针的容器:

vector<int*> vi;
vector<char*> vc;
vi.push_back( new int );
vc.push_back( new char );

实际上,不需要生成T=int*, T=char*这2套模板的代码。
void* 就可以保存任意对象的指针。

vector<void*> vi;
vector<void*> vc;
vi.push_back( new int);
vc.push_back( new char );

但这样就丢失了原来的类型。
取出时,就无法得知正确类型了。

delete vi[0]; // error, delete void*
delete vc[0]; // error, delete void*


所以,这里可以作一个偏特化。

template<typename T> // 对指针类型做偏特化
class vector<T*>
{

vector<void*> c_; // 底层容器

public:
// 转发给底层容器
push_back(T* p)
{
// 隐式类型转换,void* 可以保存任意对象指针。
return c_.push_back(p);
}

// 取出
T* operator[](size_type index)
{
void* pv = c_[index]; // c_没有类型信息
T* p = staic_cast<T*>(pv); // 但这个偏特化模板含有类型信息,还原它
return p; // 返回带有类型信息的指针。
}

...


};


现在客户代码依然这么写:

vector<int*> vi; // 底层使用vector<void*>
vector<char*> vc;
vi.push_back( new int ); // 转发函数仅含有一个隐式转换,不生成代码
vc.push_back( new char ); // inline展开,直接调用vector<void*>::push_backinline

delete vi[0]; // 调用vector<void*>::operator [](index);
delete vc[0]; // 但类型信息没有丢失

re: GUI框架:消息检查者 OwnWaterloo 2009-11-24 00:52
@cexer
【我的想法相反。你说类的灵活性不如函数加数据,但类难道不正是建立在函数和数据之上的一个超强结合体?之所以用C之类的 OP 语言实现模式不如C++这样的 OO 语言容易,一大原因正是它缺少类的支持。】

是的,类是函数和数据的结合,还加上数据隐藏。
超强到谈不上……
我也说了的,对单个object,这3门语言的OO实现确实是方便。

灵活与范化的东西,通常比较难用和不方便。



这是你举例说明的用函数来实现检查者。你可以尝试真的用函数来实现消息检查者,这个 ButtonClickingChecker(WORD id) , xxxChecker( ... ) 函数内部你各自要怎么实现?它既要包含不同的数据,又要包含不同的操作,它们返回完全相同的 message_checker 对象,这个 message_checker 又要怎么实现才能以一已之身完成众多不同的功能?由于不同参数列表的函数实际上是完全不同的东西,你甚至不能以统一的方式保存它们管理它们。

你那个MessageChecker怎么完成以一己之身完成,众多不同功能的?
同样可以应用到message_checker 上,两者是相通的,都是靠结构体中嵌的一个函数指针。


-------- -------- -------- --------

关于那个id,wp,lp,我觉得还不错。

Windows确实需要将系统与用户之间使用【一条统一的渠道【来通信。
这条渠道演化到【极端】就是这种形式:
void* (*)(void* all_parameter);

但如果所有消息都需要使用动态内存,就有点浪费。
添加一些其他比较常用的值参数 vs 和一个值参数都不用,就是一种折衷。
完全不用,肯定每次都需要动态内存分配。
值参数多了,又可能在一些情况用不上。

所以,Windows最后选择了
LRESULT (CALLBACK*)(HWND, UINT, WPARAM, LPARAM);
参数少,直接传递,参数多,将某个参数理解为指针……
(此处纯猜测……)


所以,迎合WndProc的设计还不错。


-------- -------- -------- --------

其实我是被这段语法吸引的:
window.onCreated += messageHandler( &::_handleCreated );
window.onCreated += messageHandler ( this,&Window::_handleCreated );

很像boost.signal。


而且真正吸引人的是楼主说它是廉价工人~_~


boost.function如果不用支持bind,可能可以不动用动态存储。
要支持bind…… 而且不使用动态存储…… 好像不行……
boost.signal肯定是要动用动态存储的。


等着楼主这部分的实现了~_~

re: Void and void pointer OwnWaterloo 2009-11-23 18:24
@zml_cnnk
delete操作符有2层意思。 析构和释放内存。
delete pv的话,无法推断应该调用什么析构函数。

看你的需求了。
1. 如果真的是需要析构,pv的类型再某个地方丢失了,那必须找回来。
2. 如果不需要析构,而仅仅是为了释放内存。如果是malloc分配的,那就free;如果是operator new分配的,那就operator delete;一定要配对。

re: GUI框架:消息检查者 OwnWaterloo 2009-11-23 02:45
想起一个说明限制的更通俗的例子:std::for_each。
它就算一种微型框架。
它完成了遍历的步骤,同时限制了遍历的方法—— 用一元函数。

使用for_each时
1. 直接存在现有的一元函数:
vector<void*> m; // memory blocks
for_each(m.begin(), m.end(), free );

2. 可以通过for_each配套提供的一些设施完成工作:
vector<shape*> s;
for_each(s.begin(), s.end(), bind2nd(mem_fun(&s::draw),canvas) );
for_each(s.begin(), s.end(), mem_fun(&s::reset) );

3. 扩展for_each —— 添加更多functor
vector<elem> e;
for_each(e.begin(), e.end(), boost::bind( &e::f, ... ) );

但怎么做,都只是个binder而已。还有一些人做出一些带有简单逻辑的functor,然后继续使用std::for_each,语法丑陋得,我都不知道怎么写…… 所以这里就不列了…… toplanguage上可以找到不少……

4. 当这些都失效时……
可以说,for_each这个框架在大多数时候都是鸡肋。
让人不得不绕过它的限制(传递一元函数),直接写for循环。


而boost.lambda和C++0x的lambda使得for_each变得实用了不少。所以框架是否实用,很难把握。
说for_each是框架嘛…… 主要是因为它的限制。
但是它规模有点小……也可以很轻易的被丢掉。反正是函数模板,不使用就不会被实例化。这又有类库的性质。
算是一个不太恰当的例子吧。



框架定义了轮廓线,由程序员去填充颜色。
类库提供调色板等工具,由程序员去绘制。


另外,传递给for_each的一元函数的调用语法是:
f( *first ); 而不是 ((*first).*f)();
也是一个自由函数比成员函数更普适与灵活的例子。

将成员函数以自由函数的语法进行调用:
bind(&c::f)( o, ... );

将自由函数以成员函数语法调用…… 好像要定义一个类……
共10页: 1 2 3 4 5 6 7 8 9 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(8)

随笔档案(16)

链接

搜索

  •  

积分与排名

  • 积分 - 196688
  • 排名 - 132

最新随笔

最新评论

阅读排行榜

评论排行榜