异常是程序运行时发生的非预期事件(如除零、内存不足)。C++通过try、catch和throw提供结构化处理机制,使程序能够优雅处理错误,而非直接崩溃。
核心思想:将错误处理与正常逻辑分离,提高代码可读性和健壮性。
场景:处理除零错误,抛出并捕获异常。
#include <iostream>
#include <stdexcept> // 标准异常头文件
double divide(double a, double b)
{
if (b == 0)
{
throw std::runtime_error("Error: Division by zero!");
}
return a / b;
}
int main()
{
try
{
double result = divide(10, 0);
std::cout << "Result: " << result << std::endl;
}
catch (const std::runtime_error& e)
{
std::cout << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
输出:
Caught exception: Error: Division by zero!
说明:
场景:根据错误类型抛出不同异常,并分别处理。
#include <iostream>
#include <stdexcept>
void processInput(int value)
{
if (value < 0)
{
throw std::invalid_argument("Negative value not allowed!");
}
else if (value > 100)
{
throw std::out_of_range("Value exceeds limit!");
}
// 其他逻辑
}
int main()
{
try
{
processInput(-5); // 触发invalid_argument
} catch (const std::invalid_argument& e)
{
std::cout << "Invalid Argument: " << e.what() << std::endl;
} catch (const std::out_of_range& e)
{
std::cout << "Out of Range: " << e.what() << std::endl;
} catch (...)
{
std::cout << "Unknown error!" << std::endl;
}
return 0;
}
输出:
Invalid Argument: Negative value not allowed!
说明:
场景:中间层捕获异常后记录日志,重新抛出供上层处理。
#include <iostream>
#include <stdexcept>
void lowLevel()
{
throw std::runtime_error("Low-level failure!");
}
void highLevel()
{
try
{
lowLevel();
} catch (const std::runtime_error& e)
{
std::cout << "Logged: " << e.what() << std::endl;
throw; // 重新抛出当前异常
}
}
int main()
{
try
{
highLevel();
}
catch (const std::runtime_error& e)
{
std::cout << "Main caught: " << e.what() << std::endl;
}
return 0;
}
输出:
Logged: Low-level failure!
Main caught: Low-level failure!
核心原则
场景:使用智能指针确保资源在异常发生时自动释放。
#include <iostream>
#include <memory>
#include <stdexcept>
class Resource
{
public:
Resource() { std::cout << "Resource acquired.\n"; }
~Resource() { std::cout << "Resource released.\n"; }
};
void riskyOperation()
{
auto res = std::make_unique<Resource>(); // RAII管理
throw std::runtime_error("Oops, something broke!");
// 即使抛出异常,res的析构函数也会被调用
}
int main()
{
try
{
riskyOperation();
}
catch (const std::runtime_error& e)
{
std::cout << "Error: " << e.what() << std::endl;
}
return 0;
}
输出:
Resource acquired.
Resource released.
Error: Oops, something broke!
说明:
场景:标记不抛出异常的函数。
#include <iostream>
#include <stdexcept>
void safeSwap(int& a, int& b) noexcept
{ // 保证不抛出异常
int temp = a;
a = b;
b = temp;
}
int main()
{
int x = 10, y = 20;
safeSwap(x, y);
std::cout << "x=" << x << ", y=" << y << std::endl;
return 0;
}
输出:
x=20, y=10
场景:异常抛出时,栈展开触发局部对象析构。
#include <iostream>
#include <stdexcept>
class Logger
{
public:
Logger() { std::cout << "Logger created.\n"; }
~Logger() { std::cout << "Logger destroyed.\n"; }
};
void functionB()
{
Logger log; // 局部对象
throw std::runtime_error("Error in functionB");
}
void functionA()
{
try
{
functionB();
}
catch (...)
{
std::cout << "Caught in functionA\n";
throw;
}
}
int main()
{
try
{
functionA();
}
catch (...)
{
std::cout << "Caught in main\n";
}
return 0;
}
输出:
Logger created.
Logger destroyed.
Caught in functionA
Caught in main
说明: 栈展开时,log 的析构函数被调用。
C++标准库也定义了⼀套⾃⼰的⼀套异常继承体系库,基类是exception,所以我们⽇常写程序,需要在主函数捕获exception即可,要获取异常信息,调⽤what函数,what是⼀个虚函数,派⽣类可以重写。
通过这些例子,你可以看到 C++ 异常处理的不同应用场景,包括:
这些例子展示了 C++ 异常处理机制在实际编程中的强大作用,可以帮助程序员有效地管理和应对程序运行中的错误。