仿百度文库网站源码商业版dedecms(梦织)系统内核,北京科兴中维新冠疫苗最新消息,样品门展厅设计图片,熊岳网站在哪做文章目录 一、异常处理二、枚举与联合三、嵌套类与局部类四、嵌套名字空间与匿名名字空间五、位域与volatile关键字 一、异常处理 异常处理用于处理程序在调用过程中的非正常行为。 传统的处理方法#xff1a;传返回值表示函数调用是否正常结束。 例如#xff0c;返回 0 表示… 文章目录 一、异常处理二、枚举与联合三、嵌套类与局部类四、嵌套名字空间与匿名名字空间五、位域与volatile关键字 一、异常处理 异常处理用于处理程序在调用过程中的非正常行为。 传统的处理方法传返回值表示函数调用是否正常结束。 例如返回 0 表示成功非 0 表示失败。这种方法的缺点是函数的返回值被错误处理逻辑占用不能用于其他目的。 这种方法有局限性 C 中的处理方法通过关键字 try/catch/throw 引入异常处理机制 通过 try/catch/throw 引入了结构化的错误处理机制使得错误处理逻辑与正常逻辑分离提高了代码的可读性和可维护性。 C异常处理的关键组件 throw关键字 throw 关键字用于抛出一个异常。它后面可以跟任意类型的表达式该表达式的结果将被用作异常对象 try块 try块包含了可能会抛出异常的代码。如果 try 块中的代码抛出了异常那么与之匹配的 catch 块将被执行。 catch块 catch块用于捕获并处理异常。可以有多个 catch 块来捕获不同类型的异常。 异常类 C标准库中定义了一些基本的异常类如 std::exception、std::runtime_error、std::logic_error 等
异常触发时的系统行为—栈展开 抛出异常后续的代码不会被执行 一旦抛出异常throw 语句之后的代码将不会被执行。控制流会立即转移到异常处理机制。 局部对象会按照构造相反的顺序自动销毁 在栈展开过程中局部对象包括由 new 分配的对象会按照它们构造的相反顺序自动销毁。这是为了保证资源的正确释放防止内存泄漏。 系统尝试匹配相应的 catch 代码段 如果找到匹配的 catch 块 执行 catch 块中的异常处理逻辑。异常被“捕获”后catch 块之后的代码会继续执行。 如果没有找到匹配的 catch 块 栈展开会继续进行直到找到匹配的 catch 块或者退出当前函数。 如果当前函数中没有找到匹配的 块栈展开会继续直到 找到一个匹配的 catch 块。 达到 main 函数。 如果在 main 函数之前的所有函数中都没有找到匹配的 catch 块程序将退出 main 函数。如果程序在退出 main 函数之前没有捕获到异常std::terminate 函数将被调用。这通常会导致程序立即终止。
异常对象
系统会使用抛出的异常拷贝初始化一个临时对象称为异常对象异常对象会在栈展开过程中被保留并最终传递给匹配的 catch 语句
try / catch语句块 一个 try 语句块后面可以跟一到多个 catch 语句块至少跟一个 每个 catch 语句块用于匹配一种类型的异常对象 可以有多个catch块每个用于处理不同类型的异常。 catch 语句块的匹配按照从上到下进行 catch块按照它们在代码中出现的顺序从上到下进行匹配。一旦找到匹配的异常类型就执行相应的catch块忽略后面的catch块。 使用 catch(…) 匹配任意异常 catch(...)是一个通用的异常捕获器它可以捕获任何类型的异常包括未被前面的catch块捕获的异常。 在 catch 中调用 throw 继续抛出相同的异常 在catch块中可以使用throw;不带参数来重新抛出当前捕获的异常这将导致继续搜索外层catch块。
示例
#include iostreamstruct Str{};
struct Base{};
struct Derive : Base{};void f1()
{int x;Str obj;//throw Derive{}; //打印Derive exception is called in f2 throw Str{}; //打印exception is called in f2
}void f2()
{int x2;Str obj2;try{f1();}catch(Derive e){std::cout Derive exception is called in f2 \n;}catch(Base e){std::cout Base exception is called in f2 \n;}catch(...){std::cout exception is called in f2 \n;throw; //重新抛出当前捕获的异常}std::cout other logic in f2.\n;
}void f3()
{try{f2(); }catch(Str e){std::cout exception is called in f2 \n;}
}int main()
{f3();
}在一个异常未处理完成时抛出新的异常会导致程序崩溃
不要在析构函数或 operator delete 函数重载版本中抛出异常通常来说 catch 所接收的异常类型为引用类型
异常与构造、析构函数 使用 function-try-block保护初始化逻辑 在C中function-try-block允许你在函数的初始化列表和函数体中使用try和catch。这在构造函数中特别有用因为它可以保护对象的初始化代码。 示例 #include iostreamstruct Str
{Str() { throw 100; }
}class Resource {
public:Resource() try : m_str(){}catch(int){std::cout Exception is catched at Resource::Resource std::endl;throw;}private:Str m_str;
};int main()
{try{Resource obj; }catch(int){std::cout Exception is catched at main std::endl;}
}运行结果 Exception is catched at Resource::Resource
Exception is catched at main在构造函数中抛出异常 已经构造的成员对象会被销毁 如果在构造函数中抛出异常已经构造的成员对象将按照它们构造的相反顺序自动销毁。 类本身的析构函数不会被调用 如果异常是在对象的构造过程中抛出的并且没有被捕获那么类的析构函数不会被调用。这是因为对象被视为未完全构造因此析构函数不适用。 局部对象的销毁 如果对象是局部的即在栈上异常抛出时局部对象会自动销毁但不会调用其析构函数。 动态分配对象的销毁 如果对象是动态分配的即使用new在构造函数中抛出异常且未被捕获时需要手动释放分配的内存因为析构函数不会被调用。
描述函数是否会抛出异常 如果函数不会抛出异常则应表明从而为系统提供更多的优化空间 C 98 的方式 throw() 表明不会抛出异常throw(int, char)表明可能抛出异常显式给定了要抛出异常的类型 C11 后的改进 noexcept 表明不会抛出异常noexcept(false)表明可能抛出异常不需要显式给定会抛出哪种类型的异常 noexcept 限定符接收 false / true 表示是否会抛出异常操作符接收一个表达式根据表达式是否可能抛出异常返回 false/true在声明了 noexcept 的函数中抛出异常会导致 terminate 被调用程序终止不作为函数重载依据但函数指针、虚拟函数重写时要保持形式兼容
示例
#include iostreamvoid fun2()
{}void fun() noexcept(noexcept(fun2()))
{fun2();
}int main()
{std::cout noexcept(fun()) std::endl;
}二、枚举与联合
三、嵌套类与局部类
四、嵌套名字空间与匿名名字空间
五、位域与volatile关键字