美文网首页
c++ exception

c++ exception

作者: 混世太保 | 来源:发表于2019-03-04 20:05 被阅读0次

要解决的问题:

  • exception的定义
  • throw的用法

设计习题

问题

  1. 自定义设计一个异常类?
  2. 列举c++中派生自exception的六个派生类。分别简短地说明它们的功能?
  3. throw,int类型和char*类型时,如何catch它们?
  4. catch块里为什么尽量用引用传递值而不是用值传递。那么指针传递呢?
  5. 如何在一个catch里面重新抛出该异常。?
  6. 捕获所有异常的两种方式?
  7. 如下写法存在什么问题?
catch (A& w) // 捕获Widget异常
{ // 处理异常 
    throw w; // 传递被捕获异常的拷贝
}

异常解释(exception)

当抛出一个异常时,程序会暂停当前函数的执行过程并开始寻找与异常相匹配的catch子句。当throw出现在一个try block时,检查与该try块关联的catch子句。如果找到。则进行处理。如果没找到,则继续检查与外层try匹配的catch子句。一直这样展开。直到找到为止。或者系统调用std::terminate退出主函数然后查找过程终止。这个过程称为 栈展开(stack unwinding)
在处理异常的过程中有个问题必须注意

栈展开过程中对象被自动销毁

在发生异常时,比如发生在构造函数中,可能有些成员已经初始化完了。有些成员还未初始化。则已构造的的成员,我们也要确保其能被正确地销毁。

在发生异常的函数中,析构函数总是会被执行,但是函数中释放资源的代码却可能被调用。(这是一个特性吧)

如果在析构函数中出现了异常。则可能导致该类异常退出。所以在析构函数中不应该抛出其不能处理的异常。如果确实要执行可能导致异常的操作,则该操作应该放在try语句块当中。

exception的定义

以下代码摘自faiss中的异常定义

# FaissException.h
#ifndef FAISS_EXCEPTION_INCLUDED
#define FAISS_EXCEPTION_INCLUDED

#include <exception>
#include <string>

namespace faiss {

/// Base class for Faiss exceptions
class FaissException : public std::exception {
 public:
  explicit FaissException(const std::string& msg);

  FaissException(const std::string& msg,
                 const char* funcName,
                 const char* file,
                 int line);

  /// from std::exception
  const char* what() const noexcept override;

  std::string msg;
};


/** bare-bones unique_ptr
 * this one deletes with delete [] */
template<class T>
struct ScopeDeleter {
    const T * ptr;
    explicit ScopeDeleter (const T* ptr = nullptr): ptr (ptr) {}
    void release () {ptr = nullptr; }
    void set (const T * ptr_in) { ptr = ptr_in; }
    void swap (ScopeDeleter<T> &other) {std::swap (ptr, other.ptr); }
    ~ScopeDeleter () {
        delete [] ptr;
    }
};

/** same but deletes with the simple delete (least common case) */
template<class T>
struct ScopeDeleter1 {
    const T * ptr;
    explicit ScopeDeleter1 (const T* ptr = nullptr): ptr (ptr) {}
    void release () {ptr = nullptr; }
    void set (const T * ptr_in) { ptr = ptr_in; }
    void swap (ScopeDeleter1<T> &other) {std::swap (ptr, other.ptr); }
    ~ScopeDeleter1 () {
        delete ptr;
    }
};
}
#endif

以下代码为cpp文件

#include "FaissException.h"

namespace faiss {

FaissException::FaissException(const std::string& m)
    : msg(m) {
}

FaissException::FaissException(const std::string& m,
                               const char* funcName,
                               const char* file,
                               int line) {
  int size = snprintf(nullptr, 0, "Error in %s at %s:%d: %s",
                      funcName, file, line, m.c_str());
  msg.resize(size + 1);
  snprintf(&msg[0], msg.size(), "Error in %s at %s:%d: %s",
           funcName, file, line, m.c_str());
}

const char*
FaissException::what() const noexcept {
  return msg.c_str();
}
}

自定义异常的使用方式
FaissAssert.h

#ifndef FAISS_ASSERT_INCLUDED
#define FAISS_ASSERT_INCLUDED

#include "FaissException.h"
#include <cstdlib>
#include <cstdio>
#include <string>

///
/// Assertions
///

#define FAISS_ASSERT(X)                                                 \
  do {                                                                  \
    if (! (X)) {                                                        \
      fprintf(stderr, "Faiss assertion '%s' failed in %s "              \
               "at %s:%d\n",                                            \
               #X, __PRETTY_FUNCTION__, __FILE__, __LINE__);            \
      abort();                                                          \
    }                                                                   \
  } while (false)

#define FAISS_ASSERT_MSG(X, MSG)                                        \
  do {                                                                  \
    if (! (X)) {                                                        \
      fprintf(stderr, "Faiss assertion '%s' failed in %s "              \
               "at %s:%d; details: " MSG "\n",                          \
               #X, __PRETTY_FUNCTION__, __FILE__, __LINE__);            \
      abort();                                                          \
    }                                                                   \
  } while (false)

#define FAISS_ASSERT_FMT(X, FMT, ...)                                   \
  do {                                                                  \
    if (! (X)) {                                                        \
      fprintf(stderr, "Faiss assertion '%s' failed in %s "              \
               "at %s:%d; details: " FMT "\n",                          \
               #X, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \
      abort();                                                          \
    }                                                                   \
  } while (false)

///
/// Exceptions for returning user errors
///

#define FAISS_THROW_MSG(MSG)                                            \
  do {                                                                  \
    throw FaissException(MSG, __PRETTY_FUNCTION__, __FILE__, __LINE__); \
  } while (false)

#define FAISS_THROW_FMT(FMT, ...)                                       \
  do {                                                                  \
    std::string __s;                                                    \
    int __size = snprintf(nullptr, 0, FMT, __VA_ARGS__);                \
    __s.resize(__size + 1);                                             \
    snprintf(&__s[0], __s.size(), FMT, __VA_ARGS__);                    \
    throw FaissException(__s, __PRETTY_FUNCTION__, __FILE__, __LINE__); \
  } while (false)

///
/// Exceptions thrown upon a conditional failure
///

#define FAISS_THROW_IF_NOT(X)                           \
  do {                                                  \
    if (!(X)) {                                         \
      FAISS_THROW_FMT("Error: '%s' failed", #X);        \
    }                                                   \
  } while (false)

#define FAISS_THROW_IF_NOT_MSG(X, MSG)                  \
  do {                                                  \
    if (!(X)) {                                         \
      FAISS_THROW_FMT("Error: '%s' failed: " MSG, #X);  \
    }                                                   \
  } while (false)

#define FAISS_THROW_IF_NOT_FMT(X, FMT, ...)                             \
  do {                                                                  \
    if (!(X)) {                                                         \
      FAISS_THROW_FMT("Error: '%s' failed: " FMT, #X, __VA_ARGS__);     \
    }                                                                   \
  } while (false)

#endif

在这边再简单介绍下c++的其他自己定义的异常。


1.jpg

throw的用法

throw 单独使用

throw 后面如果直接抛出异常

# 举几个例子 
# try {
#    语句组
# }
# catch(异常类型) {
#    异常处理代码
# }
# ...
# catch(异常类型) {
#     异常处理代码
# }

try{
  char str[] = "http://c.biancheng.net";
  throw str;  //数组类型
}
catch(char* p){
}

try {
      char *pstr = str;
      throw pstr;  //指针类型
}
catch(
}
catch(char* p){
}

{
  class Base{};
  Base obj;
  try {
    throw obj;  //对象类型
  }catch(Base& b){
      dosomething();
  }
}

try {
  throw 100;  //int 类型
}
catch(int i){
      dosomething();
}

相关文章

网友评论

      本文标题:c++ exception

      本文链接:https://www.haomeiwen.com/subject/rbsbuqtx.html