+ -
当前位置:首页 → 问答吧 → c++ 抛出异常到上层函数

c++ 抛出异常到上层函数

时间:2011-12-28

来源:互联网

问题1: 一直以来, 我有个意识:在代码中扑捉到异常,立即处理。

今天听人说, 这是一刀切!!! 有的异常,不能处理,需要再次抛到上层函数。。。。

最终让界面层 去处理异常, 比如:操作数据库。。。


以下是我的 的 一个例子。。。。


流程:

if(没有连接)
{

try
{

连接数据库
}

catch(_com_error e)
{
throw e; //再次抛出到上层
}

}

//已经连接上数据库
try
{

执行数据库操作
}
catch(_com_error e)
{

throw e; //抛出到上层函数
}

finally
{

关闭数据库
}





问题2.

由于c++ 没有finally,,, 

我只能这样关闭数据库:



//已经连接上数据库
try
{

执行数据库操作
}
catch(_com_error e)
{
关闭数据库
throw e; //抛出到上层函数
}

关闭数据库



看到没有,我写 关闭数据库的代码 ,得写两次。。。。




问题3: 异常对象是从而何来。。。。

举例子:

try
{
执行数据库操作
}
catch(_com_error e) //这个e是从什么来的?????
{

}

我的理解是:执行数据库的那段代码 造成的一个 _com_error对象。。。。。 这是一个临时对象!!!

e是这个临时对象 的副本!!!

不知道我的理解对不对???




三个问题,谢谢大家了啊







作者: caddor   发布时间: 2011-12-28

1. 如果所有异常下面都能处理的话, 就没有必要使用异常了. 比如打开数据库的操作, 如果它打开的时候遇到了问题自己就能处理它就不用抛出异常了, 正是在某一层上遇到了处理不了的问题才会往上一层抛出异常的.当然, 你要在某一层上把所有这一层之下的异常都处理掉也是可以的, 只要它有足够的信息来决定该如何处理它.
2. C++ 解决这个问题的方案是把释放资源的操作放到对象的析构函数函数里.在函数退出的时候就会自动执行了.
3. 异常对象通常是由 throw 语句创建的. 比如: throw some_except_class(except_argument);

作者: adlay   发布时间: 2011-12-28


1. 如果所有异常下面都能处理的话, 就没有必要使用异常了. 比如打开数据库的操作, 如果它打开的时候遇到了问题自己就能处理它就不用抛出异常了, 正是在某一层上遇到了处理不了的问题才会往上一层抛出异常的.当然, 你要在某一层上把所有这一层之下的异常都处理掉也是可以的, 只要它有足够的信息来决定该如何处理它.


这个问题 ,貌似有争议,

有人说, 异常的处理, 尽管在我这层次可以处理,但是不该我来处理,而是再抛给其他层次。。。。

所谓的 层次分明


不知道 这句话,赞同否??

尽管 大家都能处理, 






引用 1 楼 adlay 的回复:

1. 如果所有异常下面都能处理的话, 就没有必要使用异常了. 比如打开数据库的操作, 如果它打开的时候遇到了问题自己就能处理它就不用抛出异常了, 正是在某一层上遇到了处理不了的问题才会往上一层抛出异常的.当然, 你要在某一层上把所有这一层之下的异常都处理掉也是可以的, 只要它有足够的信息来决定该如何处理它.
2. C++ 解决这个问题的方案是把释放资源的操作放到对象的析构函数函数里.在函数退出……

作者: caddor   发布时间: 2011-12-28

放在析构函数中 , 对关闭数据库来说,是一个错误的处理方式


因为:

封装了一个数据库操作类。。。。 这个类 提供了一个public 函数,

主要做以下几个动作

连接,

执行

断开。。。。


不能放在析构函数中区断开。。。。 数据库的特殊性导致,即连接即断开。。。。。

放在析构函数中,只有对象要死的时候,才会断开,, 肯定不符合 即连接即断开规则。。。








引用 1 楼 adlay 的回复:

1. 如果所有异常下面都能处理的话, 就没有必要使用异常了. 比如打开数据库的操作, 如果它打开的时候遇到了问题自己就能处理它就不用抛出异常了, 正是在某一层上遇到了处理不了的问题才会往上一层抛出异常的.当然, 你要在某一层上把所有这一层之下的异常都处理掉也是可以的, 只要它有足够的信息来决定该如何处理它.
2. C++ 解决这个问题的方案是把释放资源的操作放到对象的析构函数函数里.在函数退出……

作者: caddor   发布时间: 2011-12-28

对于_com_error异常来说。。。。


你看,微软的做法,抛出异常各我, 它只是抛出, 也不会弹出什么MessageBox什么的。。。。


我捕捉到,再次抛出, 抛给界面层次

界面层的调用这,抓到异常后, 提示给用户


不知道, 这样的处理,是不是符合软件开发的 规范





引用 2 楼 caddor 的回复:
1. 如果所有异常下面都能处理的话, 就没有必要使用异常了. 比如打开数据库的操作, 如果它打开的时候遇到了问题自己就能处理它就不用抛出异常了, 正是在某一层上遇到了处理不了的问题才会往上一层抛出异常的.当然, 你要在某一层上把所有这一层之下的异常都处理掉也是可以的, 只要它有足够的信息来决定该如何处理它.


这个问题 ,貌似有争议,

有人说, 异常的处理, 尽管在我这层次可以处理,……

作者: caddor   发布时间: 2011-12-28

引用 2 楼 caddor 的回复:
1. 如果所有异常下面都能处理的话, 就没有必要使用异常了. 比如打开数据库的操作, 如果它打开的时候遇到了问题自己就能处理它就不用抛出异常了, 正是在某一层上遇到了处理不了的问题才会往上一层抛出异常的.当然, 你要在某一层上把所有这一层之下的异常都处理掉也是可以的, 只要它有足够的信息来决定该如何处理它.


这个问题 ,貌似有争议,

有人说, 异常的处理, 尽管在我这层次可以处理,……


打个比方, 一个公司有很多管理层, 当处于下层的员工的工作上出现了一些异常情况, 如果他有办法能把这个异常情况处理好, 他完全可以自己把它处理了做好记录备案, 然后一切都照常继续工作. 或者是他能处理好但是说我只管工作,不管异常情况, 然后一层一层的上报, 等到公司的经理去处理了, 然后再继续它的工作. 你觉得那种方式好些? 如果使用第二种方式, 你的顶层要处理的异常该有多少啊~~~

再说打开数据库的情况, 如果你有备用的数据库, 当主服务器连接出现异常, 完全可以在知道有备用数据库的这个层次就通过连接备用数据库来把这个异常处理了, 然后在日志里做好记录, 而不用中断程序的工作. 如果没有备用的, 那就说明这个层次是没有足够的信息来处理这个异常的, 只有返回给最高层的用户来处理了.

所以, 关键的问题在于中间的某个层次是否有足够的信息能够解决这些异常.在不能解决的情况下, 如果能够根据自己知道的信息, 对这个异常做一些处理, 然后以不同的形式再抛出这个异常也是不错的. 比如中间的某个层次在处理的时候直接把下面的异常格式化成一段消息, 然后再抛给界面层, 那么界面层就可以很简单的做一个消息显示的处理了, 而不需要在界面层去把所有的底层异常都处理一遍了.

作者: adlay   发布时间: 2011-12-28

引用 3 楼 caddor 的回复:

放在析构函数中 , 对关闭数据库来说,是一个错误的处理方式


因为:

封装了一个数据库操作类。。。。 这个类 提供了一个public 函数,

主要做以下几个动作

连接,

执行

断开。。。。


不能放在析构函数中区断开。。。。 数据库的特殊性导致,即连接即断开。。。。。

放在析构函数中,只有对象要死的时候,才会断开,, 肯定不符合 即连接即断……


你看这种方式有哪里不符合了呢?

class db_execer {
  db* pdb;
public:
  db_execer() {
  pdb->connect(...);
  }
  ~db_execer() {
  pdb->disconnect();
  }

  RES exec(...) { ... }
};


RES db_exec(command, ...)
{
  try {
  db_execer db;
  return db_exec(command....);
  }
  catch(...) {
  }
}

这样你使用的时候:
 x = db_exec(c1);
 y = db_exec(c2);
 ...
一样是每执行一次都会单独连接/断开一次.

作者: adlay   发布时间: 2011-12-28

引用 4 楼 caddor 的回复:

对于_com_error异常来说。。。。


你看,微软的做法,抛出异常各我, 它只是抛出, 也不会弹出什么MessageBox什么的。。。。


我捕捉到,再次抛出, 抛给界面层次

界面层的调用这,抓到异常后, 提示给用户


不知道, 这样的处理,是不是符合软件开发的 规范





引用 2 楼 caddor 的回复:
1. 如果所有异常下面都能处理的……


如果你捕捉后作了一些处理再次抛出是完全正常的, 如果捕捉后没有任何处理就再次抛出就没有必要了.

作者: adlay   发布时间: 2011-12-28

微软的ado 抛异常,给我,

它的信息肯定是不全的, 比如什么 3193 异常信息,就是一堆数字之类。。。。

我如果抛给界面的话,肯定是不对的,,

因为界面收到这个异常后,

用户看到后,莫名其妙的, 也不好。。。。


如你所说,  

我应该重新 抛出 字符串异常???


举例说明:



try
{

更新数据库
}

catch( _com_error e)
{

throw e; //e.Discription() 肯定是一堆数字,乱七八糟的。。。。就算我拿着这对数字,百度查询,也看不出什么来。。。

//我是不是该这么改正: throw _T("更新数据库失败!");

}



throw _T("更新数据库失败!");

 这个是抛出自定义的异常。。。。。


我听说啊, 一般是抛出对象。。。而不是抛出 字符串。。。。


我该如何 做呢???


引用 5 楼 adlay 的回复:

引用 2 楼 caddor 的回复:
1. 如果所有异常下面都能处理的话, 就没有必要使用异常了. 比如打开数据库的操作, 如果它打开的时候遇到了问题自己就能处理它就不用抛出异常了, 正是在某一层上遇到了处理不了的问题才会往上一层抛出异常的.当然, 你要在某一层上把所有这一层之下的异常都处理掉也是可以的, 只要它有足够的信息来决定该如何处理它.


这个问题 ,貌似有争议,

有人说……

作者: caddor   发布时间: 2011-12-28

是包含了格式化好的错误信息的异常对象, 最好是自己写的一个从 std::exception 继承的类, 不是直接抛出字符串...

作者: adlay   发布时间: 2011-12-28