免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 21397 | 回复: 62

[C++] 弱弱的发帖寻求开源爱好者 [复制链接]

论坛徽章:
0
发表于 2009-12-07 01:37 |显示全部楼层
小弟不才,一直想做一个C++库,拥有基础数据结构,文件,网络,线程进程,GUI等东东,
暂时没有商业用途想法,正考虑GPL或是LGPL。

基础数据结构基本从stl或是其它free软件(比如glibc)里弄来一些就行了,或者加点算法。

文件,网络,我觉得这些东西应该是一套的,都是IO设备,想做一个统一的。
就像socket描述符可以fdpoen,之后转到FILE里一样。 不过我这次想做一个C++版的,
因为C++标准库里只有文件,没有网络支持,ACE等又太复杂了,想做一个很kiss的库出来。

线程进程基本就是封装posix规定那些了,只是用C++的范型,变长模板参数等使之用起来更舒服一些。

GUI打算如下分层。。

驱动层:    需要操作系统提供一个创建窗体的办法,还有事件通知(IO事件,窗口管理器事件)
绘图层:    提供一个基本画点画线函数。(比如opengl, cairo, agg等库)
应用层:    实现类的层次结构。
想参考gnash实现,不过gnash很复杂,以我一人之力,估计要吐血。


这些东西,我基本都做了一点点尝试(GUI的代码被不小心rm了),  像是线程,线程池等是实现好了的,IO刚刚开始弄。


朋友们提醒过我,说我比较懒,立帖为证,望大家监督。

我希望把这个库做到KISS,代码与逻辑上足够清晰,接口使用上足够简洁,而且组件之间弱耦合。
若论功能,据我所了解的很多库,实现的也不过是这些功能,而且库实现的并不巧妙(并且组件之间过份耦合,导致库太大拆不开)。
如果哪位对这方面有兴趣,我很荣幸很得到您的支持。
如果谁能提供一些想法或是帮助,也不胜感激。

论坛徽章:
0
发表于 2009-12-07 01:48 |显示全部楼层
举一个现在实现了的例子说明代码的风格。
class T{
        void func( int);      
};

int main(){
        ThreadPool   tp( 10);            //最多拥有10个线程的线程池(线程数量是动态变化的)
        tp.setidletime( 0.5);             //最长空闲时间是0.5秒,就是说线程在0.5秒内没有工作,就会退出。
        tp.setidlesize(  2   );             //最多有2个线程空闲,就是说线程池里如果有3个线程没工作,就会有一个退出。

        
        T obj;
        for( int i = 0; i < 10; ++i)
           tp.run( &obj, &T::func, 2); //就是obj.func( 2),   run的参数是任意可以当成仿函数的东西。
}

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-12-07 02:11 |显示全部楼层

回复 #1 gtkmm 的帖子

请教一下,做内存管理么?

论坛徽章:
0
发表于 2009-12-07 02:16 |显示全部楼层
我现在没有做,因为我不会,而不是我不打算做。
我只是把loki里的small obj给直接拿来用了。。
如果你能帮忙,那就很感激了。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-12-07 02:21 |显示全部楼层

回复 #4 gtkmm 的帖子

我也是请教来着……

论坛徽章:
0
发表于 2009-12-07 02:45 |显示全部楼层
大牛过谦了。。

刚才在某帖看到你与一些大牛们讨论封装的问题。。
其实,我想做这个库,也是为了解决我对于封装这个问题的困惑的。

1. 有些库,不封装,根本没法用,比如xlib。
2. 还有些函数,总回某一个值表示出错,但出错的机会很小,如果这种函数被调用几十次,到处写错误处理也很烦,最可怕的还是这些出错处理是类似的,结果到处写一遍。
3. 如果函数在某种情况下要提前返回,但返回前,必须要做一些工作,比如解锁,释放内存,如果这种提前返回的地方很多,那就要写一大堆类似的函数了。
4. 有些库为了所谓的跨平台,封装的层次太深,根本没有办法调试。

对于1,只能封装了,没办法的。
对于2,某些情况应该是一个异常,但某些情况下不必。 比如read返回-1,就应该异常,而0就不必了(个人感觉)
对于3,如果那些工作由一个类来处理,就会自动析构了。
对于4,我觉得浅封装posix,先不管其它的库。 至于其它平台,那就是先用posix封装那个平台,之后就能用这个库了。

[ 本帖最后由 gtkmm 于 2009-12-7 02:47 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-12-07 05:05 |显示全部楼层

回复 #6 gtkmm 的帖子

我说说如果我遇到这些问题了,打算如何处理吧。
仅仅是讨论啊……  这种没个绝对判断标准的设计问题, 谁也别指望能说服谁   除非他自己愿意相信。
我也只是抛出自己的观点而已, 如果你觉得有点意思, 那握个手^_^ 如果觉得是胡说八道, 那你继续采取你的想法做也没关系。
我也希望能听到你的看法, 人总是狭隘的……  如果你的看法把我说服了, 我还得感谢你~_~

差不多就这个讨论基调吧……


xlib我只知道它是干什么的,不了解它具体接口是怎样的…… 据说是设计得很底层,仅提供最小化接口。
在这上面直接编程可能会比较痛苦。 所以提出一个新的概念, 让程序员在这个概念下工作, 而不接触xlib, 是有意义的。


posix我了解得多一些。我的中心想法是:与其浅包装,不如不包装。

1. 如果浅包装, 完全不懂posix是不行的吧?
既得了解一个新的库, 还要了解它底层的posix。 这很痛苦。
所以,可以假设使用该库的人, 依然必须了解posix吧?

2. 那么, 浅包装的目的何在?

2.1 绝对不应该是编写大量代码, 让 function( object, param) 的语法, 变成 object.function( param );
这很没意思。 前者同样是通过object认可的方法去操作object,而不是直接拨弄object的数据
这可能被称为数据隐藏, 不变式维护, 还有修改点限制什么的。 嗯,也是很多人口中的封装的意思。
而OO中的封装部分, 我觉得达到这点就足够了。 这就是OO中封装的核心。 object.function( param ); 只是语法样子不同而已。

而且,不一定所有c api,都可以以这种方式,转换为c++api 。
比如FILE* 和 fscanf。 c89我记得是没有vfscanf的。如果我没记错:
1. 所谓的File,要么不能实现原有的fscanf —— 功能少了
2. 要么必须把内部的FILE*暴露出来 —— 那还不如干脆不做这个事情 ……

这只是一个例子, 好像c89某个修订还是c99加入了vfscanf。

2.2 绝对不应该限制原有的功能
一旦限制了原有的功能, 当需要该功能的时候, 用户不得不抛弃一切美丽的封装, 直接访问底层。

2.3 既然完全不改变原有的编程模型, 浅包装的目的, 无非是想让某些时候编程方便一些
这里得限定一下, 所谓的浅包装, 就是该层和下层之间通常仅仅是转发,几乎不带什么多余逻辑。



如何不包装, 也能让编程方便一点?   这个只能有一说一,有二说二了…… 我一下子也想不完……
一个一个说吧。

原帖由 gtkmm 于 2009-12-7 02:45 发表
还有些函数,总回某一个值表示出错,但出错的机会很小,如果这种函数被调用几十次,到处写错误处理也很烦,最可怕的还是这些出错处理是类似的,结果到处写一遍。

嗯,这是C语言一个不太方便的地方 —— 没有异常。 没有异常会导致无法自动对某个错误保持中立
异常中立我就不多解释了,既然你打算用异常解决这个问题, 我相信你也是因为C语言在这点上让你难受了。

我的想法嘛……   在C++中真要解决"自动对错误保持中立", 那还是得用异常, 没别的办法……
但可不可以这样……   虽然有点土气……

error read(int fd,  param ); // posix
void my_read(int fd,  param ) {
        error e = read( fd, param );
        if ( has_erroe( e ) ) throw some_exception( e ) ;
}

也就是说, 不要弄到一个File类里去。 让程序员依然是在posix下工作:
int fd = open( ... );
error e = read( fd , .... ); // 我想自己处理
my_read( fd , ... ); // 我不处理

注意, 如果某个程序员对你提供的my_read中的 has_error 不满(read返回值只有0和-1?) :
他不调用my_read就可以了……  不用放弃你整个File类。
如果他觉得某种 his_has_error 是经常的情况, 他自己写一个 his_read 就ok了。



原帖由 gtkmm 于 2009-12-7 02:45 发表
3. 如果函数在某种情况下要提前返回,但返回前,必须要做一些工作,比如解锁,释放内存,如果这种提前返回的地方很多,那就要写一大堆类似的函数了。
对于3,如果那些工作由一个类来处理,就会自动析构了。

解决3这个问题, 你需要的不是一个, 而是RAII。
甚至都不是RAII, 而是RRID ——  Resource Release Is Destruction 。 这东西有现成的,Loki::ScopeGuard, 就2头文件only。MIT许可证。

f()
{

int fd = open( ... );
if ( fd is invalid ) throw ... ;

LOKI_SCOPE_EXIT(close, fd ); // 分配后成功后,立即锁住资源

char* buf = malloc( ... ); // 或者是某个可以抛出异常的版本。
if (!buf) throw ...;
LOKI_SCOPE_EXIT( free, buf );  // 分配成功后, 立即锁住资源

下面的代码中, 可以自由的使用任何跳转, 除了longjmp。

}

Loki::ScopeGuard 也有自己的缺点, 比如它是rollbackable的。很多时候并不需要回滚功能。(回滚功能会稍稍做点无用的事情)
第2个缺点, 它不能作为成员。
ScopeGuard还是不错的…… 本来我以为类似它这样的语法,没有auto是会很难看了…… 结果被Alexandrescu一个const引用搞定了……
它提供了一种思路 : 范型的RRID或者rollback。

可以在这上面发挥一下, 做一种不带rollback功能的, 可以作为成员,嵌入到内中的, 没有额外开销的, 范型RRID 。
这个我有点想法, 不过太懒……  没去深入想……  等着C++0x流行后, 有decltype会比较好办一些^_^


如果你的目的就是提供一个类……  那就继续提供吧……


原帖由 gtkmm 于 2009-12-7 02:45 发表
4. 有些库为了所谓的跨平台,封装的层次太深,根本没有办法调试。
对于4,我觉得浅封装posix,先不管其它的库。 至于其它平台,那就是先用posix封装那个平台,之后就能用这个库了。

嗯, 层次太深是让人头很大的地方……  尤其是C没有异常……  要把底层的错误给带出来……  那叫一个痛苦……
比如直接返回值代表错误含义的, 就不说了……  一层一层往上返回吧……
也有返回值仅指出对错的, 用lasterrror查询具体原因的。 这样比较容易记忆, 但依赖于tss。
还有《C 接口与实现》中模拟出的TRY, CATCH,再深入一些就差不多可以做到自动错误中立了。
不过不太敢用……  毕竟这东西,在C语言中, 算是非主流吧?  会雷焦别人的 ……


其实, 所谓的跨平台……  说穿了, 就是引入一个中间层次……
需要跨平台的人, 使用这个中间层次。 实现跨平台的人, 再每个平台下实现中间层次。

你现在是打算建立一个新的中间层次, 是吧?
其他这种库中, 也建立了中间层次, 为什么它们最后变得层次很深? 总是有点原因的…… 设计太差?


可不可以换一种方式?  完全不要这个中间层次?  其实我的意思是, 使用现有的中间层次 …… 就是posix。
然后在不支持posix的操作系统上(嗯,好像就一个), 实现posix ……
完整的posix我不了解。  我最了解的是pthread部分。 好像就几个特性没把握,其他都可以实现。
比如barrier, 这应该要涉及汇编, 不懂……
比如cancel机制,我不太了解pthread中这个cancel机制……   这是和win32 不同的一个地方, win32没有这种东西。
有cancel的编程经验后, 应该也不难。

这样的话,写的是pthread代码(比较多的人熟悉), 在win32下链接一个库(逃不掉的工作),在posix下,几乎不用你做什么多余的事情,链接pthread即可……


我知道有个pthread-win32的库……  不过对他有些地方不太满意。
比如它几乎所有对象都动用了动态内存, 而内部又使用malloc …… 二进制兼容性可以通过其他方式解决, 不透明指针类型不是唯一的办法。
比如它实现STATIC_INITIALIZER的方式 ……  虽然我个人觉得pthread的STATIC_INITIALIZER就是一个错误……  至少应该将它降级为optional。
我讨厌这种 get_and_init语意的接口。 用起来确实会爽一点点, 但不用也死不了。
要实现这种 get_and_init语意的接口, 会遭到很多很多麻烦。

心里隐约有一个依然是get_and_init;但是一旦init完成,以后的get_and_init调用就不再需要if测试,仅仅get的方案。
应该是可以实现的。 具体没仔细想。


稍微大点的库,都要用到动态内存分配的。 很多库就很不负责的直接使用malloc了 ……
所以我一开始就是问你对这个有没有什么想法…… loki.smallobj 在我的毕业论文里被批得半死, 哈哈哈
底层要么用malloc, 要么用new, 没别的定制方式; 那个独特的char index设计, 让chunk数量增多; vector<chunk> 本身就要消耗动态内存 ……

有一点可以改进的地方, 就是归还时, 找block 所属chunk, 可以将chunk组织为树,就不需要线性查找。
Alexandrescu大牛在MCD里将归还情况分析来分析去的, 居然没想到这个……  不知道是不是考虑移植性问题了……
当然, i386下肯定没问题, 其他平台下 …… 指针的比较语意是怎样定义的我不清楚了……

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-12-07 05:21 |显示全部楼层

回复 #6 gtkmm 的帖子

哦,  好像有个地方理解错了 ……

你是为了建立一个中间层次, 屏蔽各种posix实现之间的差异?
如何屏蔽?  取交集?  那直接取posix的交集好了 ……

如果比交集多,需要自己实现一部分属于posix又不被目标平台支持的接口的话,使用一个中间层次可能带来的困扰会少一些。
但还是尽可能维持和posix差不多的样子吧,以减少学习成本。
核心部分也别做成C++吧 ……  让C程序员也沾沾光,用用

说来说去……  如果按这个方向发展下去……  那就是apr了 ……
如果加上C++接口, 那就是boost了 ……

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
发表于 2009-12-07 08:36 |显示全部楼层
包含太多内容的封装的库往往没有市场,我不想为了其中的一点内容而包含一大坨东西,而且不同项目需求不同,要用一种封装符合多种需求不现实。

论坛徽章:
0
发表于 2009-12-07 09:45 |显示全部楼层

回复 #9 hellioncu 的帖子

同意这位大哥的看法,要写一个小而且精,而且有创意的东西。
将来一定要能赚钱。。。买房阿。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP