免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6164 | 回复: 10
打印 上一主题 下一主题

[请问]c++里面有set_new_handler,c里面怎么办? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-01-06 18:04 |只看该作者 |倒序浏览
想要一劳永逸的解决每次分配内存以后判断退出条件的问题。
(1)
new或malloc以后判断返回是否是0
但是我的工程里面有N多类,N多函数,N多个地方有内存的操作(不是所有内存操作都被封装到了ctor/dtor里面)。c++里面我可以在main的开始调用一次set_new_handler然后粗暴的退出程序(最简单的处理方法),以后的代码不用每次new的时候都去做一个判断了。c里面有对应方法吗????????????????
(2)
又牵扯到另外一个问题,例如我有一个很简单的c程序,用来打开一个文件写入一堆字符,如果要写的健壮,那么代码的大头就成了错误处理,判断fopen,fwrite是否成功。但是这样的工作每次都重复。有没有像set_new_handler那样的懒惰方法,能大规模的减少重复劳动?
(3)
可能这个问题不仅是c/c++,随便哪个编成语言看起来(听说Lisp除外)都是错误处理代码比功能实现代码更多。

望指教!

论坛徽章:
0
2 [报告]
发表于 2009-01-06 18:24 |只看该作者
写成函数封装一下,APUE上好像就这么干的。

论坛徽章:
0
3 [报告]
发表于 2009-01-06 18:32 |只看该作者
to2楼:
我怎么觉得是unix network programming 是这么做的啊

论坛徽章:
0
4 [报告]
发表于 2009-01-06 18:47 |只看该作者

回复 #1 jeanlove 的帖子

在实际的工作中,象malloc、open等常用函数都会自己包一下,加上判返回值的部分,然后来使用的。

论坛徽章:
0
5 [报告]
发表于 2009-01-06 22:54 |只看该作者
lz,没看明白你在说什么,你是否可以先说说set_new_handler是做什么的或者为什么要使用set_new_handler?

论坛徽章:
0
6 [报告]
发表于 2009-01-07 09:17 |只看该作者
自己包装一下,自己包装的函数想要加什么功能还不简单啊

论坛徽章:
0
7 [报告]
发表于 2009-01-07 09:21 |只看该作者
原帖由 jeanlove 于 2009-1-6 02:04 发表
想要一劳永逸的解决每次分配内存以后判断退出条件的问题。
(1)
new或malloc以后判断返回是否是0
但是我的工程里面有N多类,N多函数,N多个地方有内存的操作(不是所有内存操作都被封装到了ctor/dtor里面)。c+ ...


你加个new_handler里面退出程序,还不如new不到内存直接让程序崩掉?

论坛徽章:
0
8 [报告]
发表于 2009-01-07 09:35 |只看该作者
达到set_new_handler的函数好像没有把,我刚才找了一下, 在new失败 throw 错误之前,会调用set_new_handler注册的函数。但是在c中用的是malloc没有办就没有办法了

论坛徽章:
0
9 [报告]
发表于 2009-01-07 10:11 |只看该作者
原帖由 chentao_612 于 2009-1-7 09:35 发表
达到set_new_handler的函数好像没有把,我刚才找了一下, 在new失败 throw 错误之前,会调用set_new_handler注册的函数。但是在c中用的是malloc没有办就没有办法了


嗯,似乎是没有很好的解决方法。
那既保险又能偷懒的方法就是包装基本*nix函数而且遇到错误,就让打印出一个比较详细的错情况并且让程序立即exit了? 这样主程序里面就不用大量的针对语言本身的错误处理代码了,逻辑就能清晰很多。

能改进不?

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
10 [报告]
发表于 2009-01-07 10:32 |只看该作者
set_new_handler的作用是:
1、尝试“变”出更多内存,让系统可以继续运行下去(避免抛异常)
2、发现内存不足了,就提示用户/记录日志/保存数据,暂时延缓异常的抛出


所以,set_new_handler的返回值是上一次设置的new_handler(一般是系统默认的那个);这些new_handler每被调用一次,都应该恢复在它之前那个new_handler。


举例来说,我先保留2M内存,然后写了个my_new_handler;这个函数会释放这2M内存,然后恢复全局区保存的上一个new_handler。
这样,一旦第一次申请内存失败,my_new_handler就会“交”出2M内存,然后恢复上一个new_handler;如果这样仍然不能让new成功,那么系统就会再次调用当前new_handler,直到内存分配成功或者当前new_handler返回失败:

//伪码,实际可能有所差别
void * new(size_t size)
{
      do
      {
            void * p = malloc(size);
            if ( p == null )
            {
                 //内存分配失败,调用new_handle看能否搞到更多内存
           //如果new_handle返回false,直接抛异常;否则继续循环
                 if ( _call_new_handle() == false )
                      throw ...;
            }
            else
            {
                   return p;
            }
       } while(true);
}

系统默认的new_handler已经完成了抛异常这个任务(除非用编译器选项明确关上),所以没必要(也不应该)写自己的new_handler完成退出,因为这可能导致别人无法catch到new抛出的异常。
——————————————————————

在c里,可以参考上面的逻辑自己实现——不过throw要改成exit(ERR_MALLOC_FAILED)


——————————————————————
错误处理代码多于功能代码这个问题要看发生在什么地方。

多数情况下,不涉及网络、文件、资源申请以及其他可能不稳定的软硬件的调用,在传入参数正确时,是可以做到100%正确的。

比如,to_upper/sscanf/sqrt等等——除非你给sqrt传入了负值(不考虑虚数),它必定是可以返回正确结果的。

这类问题的根本原因是程序员糊涂了,必须让他改正,而不是用“容错”代码把这个大乌龙固定到源代码里。


同样,数据库里合理设置约束后,有用户名查不到资料这种情况必然是不会出现的——数据库本身的定义就决定了这点。
这时候,检查一个用户有多个资料、用户存在但select用户详细资料不成功等等错误就是没必要的,更不要为它写容错流程——assert一下就足够了。

一旦你为这些东西写了容错,那么你就不得不为这些容错的东西容错。这样项目自然复杂度失控,bug永远查不完。

[ 本帖最后由 shan_ghost 于 2009-1-7 10:37 编辑 ]

评分

参与人数 1可用积分 +2 收起 理由
jeanlove + 2 shan_ghost兄,我对你佩服的五体投地。 ...

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP