c-异常处理2
目录
c++ 异常处理2
以下通过更多具体示例详细说明C++异常处理机制:
一、基础异常处理示例
示例1:基础try-catch结构
#include <iostream>
#include <stdexcept>
void checkAge(int age) {
if (age < 18) throw std::out_of_range("Age too small");
if (age > 120) throw std::invalid_argument("Age too large");
}
int main() {
try {
checkAge(15); // 抛出std::out_of_range
} catch (const std::out_of_range& e) {
std::cout << "Range Error: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cout << "General Error: " << e.what() << std::endl;
}
}
/* 输出:
Range Error: Age too small */
示例2:catch(…) 通用捕获
void riskyOperation() {
throw "Unknown error type"; // 抛出C风格字符串
}
int main() {
try {
riskyOperation();
} catch (const std::exception& e) {
std::cout << "Standard exception: " << e.what();
} catch (...) { // 捕获任意类型异常
std::cout << "Unknown exception caught!";
}
}
/* 输出:
Unknown exception caught! */
二、栈展开与对象生命周期
示例3:局部对象析构顺序
class Trace {
int id;
public:
Trace(int i) : id(i) { std::cout << "Create " << id << "\n"; }
~Trace() { std::cout << "Destroy " << id << "\n"; }
};
void funcC() {
Trace t3(3);
throw std::runtime_error("Boom!");
}
void funcB() {
Trace t2(2);
funcC();
}
void funcA() {
Trace t1(1);
funcB();
}
int main() {
try {
funcA();
} catch (...) {
std::cout << "Exception handled\n";
}
}
/* 输出:
Create 1
Create 2
Create 3
Destroy 3 // 反向析构顺序
Destroy 2
Destroy 1
Exception handled */
三、异常与构造函数
示例4:构造函数部分构造
class Member {
public:
Member() { std::cout << "Member constructed\n"; }
~Member() { std::cout << "Member destroyed\n"; }
};
class Problematic {
Member m1, m2;
public:
Problematic() : m1(), m2() {
throw std::bad_alloc(); // 抛出异常
}
~Problematic() {
std::cout << "Problematic destroyed\n"; // 不会执行
}
};
int main() {
try {
Problematic obj;
} catch (...) {
std::cout << "Construction failed\n";
}
}
/* 输出:
Member constructed
Member constructed
Member destroyed // m2析构
Member destroyed // m1析构
Construction failed */
四、noexcept关键字的应用
示例5:noexcept函数中的非法操作
void noThrowFunc() noexcept { // 承诺不抛异常
throw 42; // 违反noexcept约定
}
int main() {
noThrowFunc(); // 触发std::terminate()
}
// 程序直接崩溃,无法捕获异常
示例6:noexcept条件判断
void mayThrow() { throw 42; }
void noThrow() noexcept {}
static_assert(noexcept(noThrow())); // 通过
static_assert(!noexcept(mayThrow())); // 通过
template<typename F>
void callSafely(F func) noexcept(noexcept(func())) {
func();
}
int main() {
callSafely(noThrow); // 安全调用
callSafely(mayThrow); // 若抛出异常,触发terminate
}
五、自定义异常类型
示例7:继承标准异常
#include <exception>
#include <string>
class NetworkException : public std::exception {
std::string msg;
public:
NetworkException(const std::string& host)
: msg("Connection failed: " + host) {}
const char* what() const noexcept override {
return msg.c_str();
}
};
void connectServer(const std::string& host) {
throw NetworkException(host);
}
int main() {
try {
connectServer("example.com");
} catch (const NetworkException& e) {
std::cout << "Network Error: " << e.what();
}
}
/* 输出:
Network Error: Connection failed: example.com */
六、异常安全与RAII
示例8:文件资源管理
#include <fstream>
#include <vector>
class FileGuard {
std::fstream file;
public:
FileGuard(const std::string& name)
: file(name, std::ios::out) {
if (!file) throw std::runtime_error("File open error");
}
~FileGuard() {
if (file.is_open()) {
file.close();
std::cout << "File released\n";
}
}
void write(const std::string& data) {
file << data;
if (!file) throw std::runtime_error("Write error");
}
};
void processFile() {
FileGuard fg("data.txt");
fg.write("Hello World");
throw std::runtime_error("Simulated error after write");
}
int main() {
try {
processFile();
} catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
}
}
/* 输出:
File released // 异常发生时自动关闭文件
Error: Simulated error after write */
七、异常重抛与嵌套处理
示例9:异常重抛与上下文添加
void innerFunction() {
throw std::runtime_error("Original error");
}
void outerFunction() {
try {
innerFunction();
} catch (...) {
std::cout << "[LOG] Error occurred in innerFunction\n";
throw; // 重抛原始异常
}
}
int main() {
try {
outerFunction();
} catch (const std::runtime_error& e) {
std::cout << "Caught: " << e.what();
}
}
/* 输出:
[LOG] Error occurred in innerFunction
Caught: Original error */
总结表格
场景 | 关键行为 | 最佳实践 |
---|---|---|
构造函数异常 | 已构造的成员/基类会被析构,当前对象析构函数不执行 | 使用RAII管理成员资源 |
析构函数异常 | 若未捕获会导致terminate() | 析构函数必须标记为 noexcept |
异常捕获顺序 | 按catch块顺序匹配,基类异常应放在子类之后 | 先捕获具体异常,后捕获通用异常 |
noexcept函数 | 违反约定会导致程序终止 | 仅对真正不抛异常的函数使用 noexcept |
异常对象 | 通过拷贝初始化,按值/引用捕获影响效率 | 优先使用 const & 捕获异常 |