C++中try/catch/throw的使用

本文介绍了C++中的异常处理机制,包括throw表达式、try语句块和异常类等内容。通过示例代码展示了如何使用try、catch和throw关键字来检测和处理运行时错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++异常是指在程序运行时发生的反常行为,这些行为超出了函数正常功能的范围。当程序的某部分检测到一个它无法处理的问题时,需要用到异常处理。异常提供了一种转移程序控制权的方式。C++异常处理涉及到三个关键字:try、catch、throw。

在C++语言中,异常处理包括:

(1)、throw表达式:异常检测部分使用throw表达式来表示它遇到了无法处理的问题,throw引发了异常。throw表达式包含关键字throw和紧随其后的一个表达式,其中表达式的类型就是抛出的异常类型。throw表达式后面通常紧跟一个分号,从而构成一条表达式语句。

(2)、try语句块:异常处理部分使用try语句块处理异常。try语句块以关键字try开始,并以一个或多个catch子句结束。try语句块中代码抛出的异常通常会被某个catch子句处理。因为catch子句处理异常,所以它们也被称作异常处理代码。catch子句包括三部分:关键字catch、括号内一个(可能未命名的)对象的声明(称作异常声明,exception  declaration)以及一个块。当选中了某个catch子句处理异常之后,执行与之对应的块。catch一旦完成,程序跳转到try语句块最后一个catch子句之后的那条语句继续执行。try语句块声明的变量在块外部无法访问,特别是在catch子句内也无法访问。如果一段程序没有try语句块且发生了异常,系统会调用terminate函数并终止当前程序的执行。

(3)、一套异常类(exception class):用于在throw表达式和相关的catch子句之间传递异常的具体信息。

C++标准库定义了一组类,用于报告标准库函数遇到的问题。这些异常类也可以在用户编写的程序中使用,它们分别定义在4个头文件中:

(1)、exception头文件定义了最通常的异常类exception,它只报告异常的发生,不提供任何额外的信息。

(2)、stdexcept头文件定义了几种常用的异常类,如下(《C++ Primer(Fifth Edition)》):

(3)、new头文件定义了bad_alloc异常类型。

(4)、type_info头文件定义了bad_cast异常类型。

Exceptions provide a way to react to exceptional circumstances (like run time errors) in programs by transferring control to special functions called handlers.

To catch exceptions, a portion of code is placed under exception inspection. This is done by enclosing that portion of code in a try-block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are ignored.

An exception is thrown by using the throw keyword from inside the try block. Exception handlers are declared with the keyword catch, which must be placed immediately after the try block.

The C++ Standard library provides a base class specifically designed to declare objects to be thrown as exceptions. It is called std::exception and is defined in the<exception> header. This class has a virtual member function called what that returns a null-terminated character sequence (of type char *) and that can be overwritten in derived classes to contain some sort of description of the exception.

C++provides a list of standard exceptions defined in <exception> ( https://www.tutorialspoint.com/cplusplus/cpp_exceptions_handling.htm ):

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "try_catch.hpp"
#include <iostream>
#include <exception>
#include <vector>

//////////////////////////////////////////////////
// reference: http://www.cplusplus.com/doc/tutorial/exceptions/
int test_exception1()
{
	try {
		throw 20;
	}
	catch (int e) {
		std::cout << "An exception occurred. Exception Nr. " << e << '\n';
	}

	return 0;
}

class myexception : public std::exception
{
	virtual const char* what() const throw()
	{
		return "My exception happened";
	}
} myex;

int test_exception2()
{
	try {
		throw myex;
	}
	catch (std::exception& e) { // catches exception objects by reference (notice the ampersand & after the type)
		std::cout << e.what() << '\n';
	}

	return 0;
}

int test_exception3()
{
/*
	exception		description
	bad_alloc		thrown by new on allocation failure
	bad_cast		thrown by dynamic_cast when it fails in a dynamic cast
	bad_exception		thrown by certain dynamic exception specifiers
	bad_typeid		thrown by typeid
	bad_function_call	thrown by empty function objects
	bad_weak_ptr		thrown by shared_ptr when passed a bad weak_ptr
*/
	try {
		int* myarray = new int[1000];
	}
	catch (std::exception& e) { // Takes a reference to an 'exception' object
		std::cout << "Standard exception: " << e.what() << std::endl;
	}

	return 0;
}

///////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/language/try_catch
int test_exception4()
{
	try {
		std::cout << "Throwing an integer exception...\n";
		throw 42;
	}
	catch (int i) {
		std::cout << " the integer exception was caught, with value: " << i << '\n';
	}

	try {
		std::cout << "Creating a vector of size 5... \n";
		std::vector<int> v(5);
		std::cout << "Accessing the 11th element of the vector...\n";
		std::cout << v.at(10); // vector::at() throws std::out_of_range
	}
	catch (const std::exception& e) { // caught by reference to base
		std::cout << " a standard exception was caught, with message '"
			<< e.what() << "'\n";
	}

	return 0;
}

/////////////////////////////////////////////////
// reference: https://www.tutorialspoint.com/cplusplus/cpp_exceptions_handling.htm
static int division(int a, int b) {
	if (b == 0) {
		throw "Division by zero condition!";
	}
	return (a / b);
}

int test_exception5()
{
	int x{ 50 }, y{ 0 }, z{ 0 };

	try {
		z = division(x, y);
		std::cout << z << std::endl;
	}
	catch (const char* msg) {
		std::cerr << msg << std::endl;
	}

	return 0;
}

struct MyException : public std::exception
{
	const char * what() const throw () {
		return "C++ Exception";
	}
};

int test_exception6()
{
	try {
		throw MyException();
	}
	catch (MyException& e) {
		std::cout << "MyException caught" << std::endl;
		std::cout << e.what() << std::endl;
	}
	catch (std::exception& e) {
		//Other errors
	}

	return 0;
}

int test_exception7()
{
	try {
		char* str = nullptr;
		str = new char[10];
		if (str == nullptr) throw "Allocation failure";
		for (int n = 0; n <= 100; n++) {
			if (n > 9) throw n;
			str[n] = 'z';
		}
	}
	catch (int i) {
		std::cout << "Exception: ";
		std::cout << "index " << i << " is out of range" << std::endl;
	}
	catch (char * str) {
		std::cout << "Exception: " << str << std::endl;
	}

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

使用 `try/catch` 时遇到问题,通常与异常捕获的范围、类型以及语言特性有关。以下是一些常见问题及其解决方案: ### 1. 捕获系统级异常(如段错误、除零等) 在 C++ 中,标准的 `try/catch` 只能捕获通过 `throw` 抛出的异常,并不能处理系统级异常,例如访问非法内存地址或除以零等操作。为了解决这类问题,可以使用 Windows 特有的 **结构化异常处理**(SEH),即 `__try/__except` 块来捕获硬件异常[^1]。 ```cpp #include <windows.h> __try { // 可能引发异常的代码 int a = 5 / 0; } __except (EXCEPTION_EXECUTE_HANDLER) { printf("捕获到除零异常\n"); } ``` 对于 Qt 程序员,虽然 `QT_TRY/QT_CATCH` 是兼容 SEH 的封装,但在某些情况下仍无法替代原生 SEH 处理机制。 ### 2. PHP 中无法捕获致命错误 PHP 的 `try/catch` 在早期版本中仅能捕获 `Exception` 类型的异常,而无法捕获致命错误(如 `E_ERROR`)。从 PHP 7 开始,很多致命错误被转换为 `Error` 实例,它们实现了 `Throwable` 接口,因此可以通过如下方式统一捕获: ```php try { // 可能抛出异常或错误的代码 } catch (\Throwable $t) { echo "捕获到异常或错误:" . $t->getMessage(); } ``` 此外,若设置了自定义错误处理器(如 `set_error_handler()`),但未将其转换为异常,则这些错误也不会进入 `try/catch` 流程中。 ### 3. Java 中局部变量作用域问题 在 Java 中,如果在 `try` 块内部声明变量,外部将无法访问该变量。为避免此类编译错误,应在 `try/catch` 外部声明变量,并在块内进行赋值: ```java public void test() { String result = null; try { result = JsonUtils.object2Json(map); } catch (IOException e) { e.printStackTrace(); } System.out.println(result); // 正常引用 } ``` 此做法确保了变量的作用域足够宽泛,可被后续代码访问[^3]。 ### 4. JavaScript Promise 异常捕获失败 在异步编程中,直接对 `Promise.reject()` 使用 `try/catch` 是无效的,因为 `Promise` 错误是异步触发的。应使用 `.catch()` 方法或者 `await` 配合 `try/catch` 来正确捕获异常: ```javascript async function f2() { try { await new Promise((resolve, reject) => { reject('出错了'); }); } catch (e) { console.log(e); // 成功捕获 } } f2(); ``` 如果不使用 `await`,则需通过链式调用 `.catch()` 来处理错误: ```javascript function f2() { Promise.reject('出错了') .catch(e => console.log(e)); // 捕获并处理错误 } ``` ### 5. Spring Boot Service 层数据库异常捕获失效 当将数据库操作逻辑从 Controller 层移动至 Service 层后,可能出现异常捕获失效的问题。这通常是由于事务管理配置不当导致的。Spring 默认不会将异常传播到上层,除非明确声明事务回滚策略。 解决方法包括: - 使用 `@Transactional(rollbackFor = Exception.class)` 注解,强制事务在所有异常下回滚。 - 明确抛出受检异常或运行时异常,确保异常能够穿透事务代理。 - 若需要自定义异常处理逻辑,建议结合 `@ControllerAdvice` 或 `@ExceptionHandler` 进行全局异常管理。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值