【C++】异常,你了解了吗?(二)

简介: 在之前的C语言处理错误时,会通过assert和错误码的方式来解决,这导致了发生错误就会直接把程序关闭,或者当调用链较长时,就会一层一层的去确定错误码,降低效率,所以c++针对处理错误,出现了异常,一起来学习!

随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。

这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了。

这就有了用子类抛异常,父类来捕获异常。什么意思呢?来看例子:

//规定一个异常的标准类
class Exception
{
public:
  Exception(const string& errmsg, int id)
    :_errmsg(errmsg)
    , _id(id)
  {}
  virtual string what() const
  {
    return _errmsg;
  }
protected:
  string _errmsg;
  int _id;
};
//我么们可以通过继承父类后,增加子类的成员变量来区分异常类型
class SqlException : public Exception
{
public:
  SqlException(const string& errmsg, int id, const string& sql)
    :Exception(errmsg, id)
    , _sql(sql)
  {}
  virtual string what() const
  {
    string str = "SqlException:";
    str += _errmsg;
    str += "->";
    str += _sql;
    return str;
  }
private:
  const string _sql;
};
class CacheException : public Exception
{
public:
  CacheException(const string& errmsg, int id)
    :Exception(errmsg, id)
  {}
  virtual string what() const
  {
    string str = "CacheException:";
    str += _errmsg;
    return str;
  }
};
class HttpServerException : public Exception
{
public:
  HttpServerException(const string& errmsg, int id, const string& type)
    :Exception(errmsg, id)
    , _type(type)
  {}
  virtual string what() const
  {
    string str = "HttpServerException:";
    str += _type;
    str += ":";
    str += _errmsg;
    return str;
  }
private:
  const string _type;
};
void SQLMgr()
{
  srand(time(0));
  if (rand() % 7 == 0)
  {
    throw SqlException("权限不足", 100, "select * from name = '张三'");
  }
  cout << "调用成功" << endl;
}
void CacheMgr()
{
  srand(time(0));
  if (rand() % 5 == 0)
  {
    throw CacheException("权限不足", 100);
    //throw 1;
  }
  else if (rand() % 6 == 0)
  {
    throw CacheException("数据不存在", 101);
  }
  SQLMgr();
}
void HttpServer()
{
  // ...
  srand(time(0));
  if (rand() % 3 == 0)
  {
    throw HttpServerException("请求资源不存在", 100, "get");
  }
  else if (rand() % 4 == 0)
  {
    throw HttpServerException("权限不足", 101, "post");
  }
  CacheMgr();
}
int main()
{
  while (1)
  {
    Sleep(1000);
    try 
        {
      HttpServer();
    }
    catch (const Exception& e) // 这里捕获父类对象就可以
    {
      // 多态
      cout << e.what() << endl;
    }
    catch (...)
    {
      cout << "Unkown Exception" << endl;
    }
  }
  return 0;
}

可以来看一下结果:

catch(...){}的作用就是方式其他无匹配的异常类型报错停止程序。


这里其实也用到了多态的调用,通过父类的引用,来调用重写以后的虚函数,从而实现多态调用。


这就很好的解决了问题。



C++ 提供了一系列标准的异常 ,我们可以在程序中使用这些标准的异常。

但是

实际中我们可以可以去继承 exception 类实现自己的异常类。但是实际中很多公司像上面一

样自己定义一套异常继承体系。因为 C++ 标准库设计的不够好用。

只需知道这些异常代表的意义:

(申请内存空间)

(越界访问)

5.异常安全

1.构造函数完成对象的构造和初始化,最好不要在构造函数中抛出异常,否则可能导致对象不

完整或没有完全初始化

2.析构函数主要完成资源的清理,最好不要在析构函数内抛出异常,否则可能导致资源泄漏(内

存泄漏、句柄未关闭等)

3.C++中异常经常会导致资源泄漏的问题,比如在new和delete中抛出了异常,导致内存泄

漏,在lock和unlock之间抛出了异常导致死锁,C++经常使用RAII来解决以上问题,关于RAII

会在智能指针进行讲解。(我们下期再见)

6.异常的优缺点

优点:


1. 异常对象定义好了,相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包含堆栈调用的信息,这样可以帮助更好的定位程序的bug。


2. 返回错误码的传统方式有个很大的问题就是,在函数调用链中,深层的函数返回了错误,那

么我们得层层返回错误,最外层才能拿到错误。但C++的异常可以直接跳转到捕获异常的位置。

错误码返回要层层判断,当前遇到错误,返回上一层要判断返回的错误码。

缺点:


1. 异常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳。这会

导致我们跟踪调试时以及分析程序时,比较困难。

2. 异常会有一些性能的开销。当然在现代硬件速度很快的情况下,这个影响基本忽略不计。

3. C++没有垃圾回收机制,资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异常

安全问题。这个需要使用RAII来处理资源的管理问题。学习成本较高。

总之,利大于弊!

目录
相关文章
|
6月前
|
算法 编译器 C语言
【C++ 异常】C++ 标准库异常类及其应用
【C++ 异常】C++ 标准库异常类及其应用
76 0
|
6月前
|
C++
C++ 捕获所有异常并拿到错误原因的方法
C++ 捕获所有异常并拿到错误原因的方法
182 0
|
6月前
|
安全 算法 C++
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误(三)
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误
134 0
|
6月前
|
存储 安全 算法
【C/C++ 关键字 函数说明符 】C++ noexcept 关键字(指定某个函数不抛出异常)
【C/C++ 关键字 函数说明符 】C++ noexcept 关键字(指定某个函数不抛出异常)
77 0
|
6月前
|
SQL 安全 程序员
C++:异常
C++:异常
58 7
|
6月前
|
小程序 编译器 Linux
C++ 异常原理:以一个小程序为例
作者在调查某个 bug 时涉及到 C++ 异常,借此机会以本文把 C++ 异常机制梳理清楚供大家参考。
|
6月前
|
安全 Java 程序员
【C++】异常 -- 详解
【C++】异常 -- 详解
|
4月前
|
C++
C++ 异常机制问题之捕获异常的问题如何解决
C++ 异常机制问题之捕获异常的问题如何解决
|
4月前
|
安全 Java 程序员
【C++11】异常知多少
【C++11】异常知多少
41 7
|
6月前
|
缓存 安全 Java
从C语言到C++_35(异常)C++异常的使用+异常体系+异常优缺点(下)
从C语言到C++_35(异常)C++异常的使用+异常体系+异常优缺点
51 7