new 捕获所有异常 避免内存泄漏

本文讨论了在C++编程中,如何使用原始指针捕获所有异常以避免内存泄漏的问题。通过示例展示了在可能出现异常的情况下,手动管理内存可能导致资源泄漏,推荐使用智能指针以简化代码并确保资源正确释放。

原始指针 捕获所有异常 避免内存泄漏

原始指针 避免内存泄漏

程序使用 raw pointer 时,资源往往被显式管理(managed explicitly)。以此方式使用 raw pointer 的典型例子是,以 newdelete 创建和销毁对象:

void Foo()
{
	Widget* ptr = new Widget;	// create an object explicitly

	// ... perform some operations(may throw exceptions)

	delete ptr;			// clean up(destroy the object explicitly)
}

这个函数将成为麻烦制造者。一个明显的问题是,有可能忘记 delete 对象,特别是如果你在函数中有个 return 语句。另一个较不明显的危险是它可能抛出异常,那将立刻退离(exit)函数,末尾的 delete 语句也就没机会被调用,导致内存泄漏,或更一般性地说,资源泄漏。

为了避免如此的资源泄漏,通常函数会捕捉所有异常,例如:

void Foo()
{
	Widget* ptr = new Widget;

	try
	{
		// perform some operations...(may throw exceptions)
		std::string().at(1);	// this generates an std::out_of_range
	}
	catch (...)			// for any exception
	{
		delete ptr;		// clean up
		throw;			// rethrow the exception
	}

	delete ptr;			// clean up on normal end
}

为了在异常发生时能够适当处理好对象的删除,代码变得比较复杂,而且累赘。如果第二个对象也以此方式处理,或需要一个以上的 catch 子句,情况会变得更糟。这是一种不好的编程风格,应该避免,因为它复杂而又容易出错。 对此, smart pointer 可以带来帮助。 Smart pointer 可以在它自身被销毁时释放其所指向的数据——不论是正常结束或异常结束。现代 C++ 程序应该优先使用智能指针。

完整程序

#include <iostream>
#include <new>

class Widget { double d[1024]; /* ... */ };

void Foo()
{
	Widget* ptr = new Widget;

	try
	{
		// perform some operations...(may throw exceptions)
		std::string().at(1);	// this generates an std::out_of_range
	}
	catch (...)			// for any exception
	{
		delete ptr;		// clean up
		throw;			// rethrow the exception
	}

	delete ptr;			// clean up on normal end
}

int main()
{
	try
	{
		Foo();
	}
	catch (const std::bad_alloc& err)
	{
		std::cout << err.what() << std::endl;
	}
	catch (const std::exception& err)
	{
		std::cout << err.what() << std::endl;
	}
	catch (...)
	{
		std::cout << "unknown exceptions" << std::endl;
	}

	return 0;
}
### C++ 程序意外退出时 new 分配的内存是否会引发内存泄漏C++ 中,当程序意外退出(例如由于未捕获异常或调用 `std::terminate`)时,动态分配的内存通常不会被自动释放。这是因为 C++ 的标准并未规定在程序非正常终止时必须执行资源清理操作。因此,使用 `new` 分配的内存如果没有显式调用 `delete` 来释放,这部分内存将无法被回收[^1]。 然而,需要注意的是,内存泄漏的概念主要针对程序运行期间未能释放的内存资源。如果程序意外退出,操作系统通常会回收该进程所占用的所有资源,包括堆内存。这意味着从操作系统的角度来看,虽然程序内部存在未释放的内存,但这些内存并不会永久丢失,而是会在进程终止后由操作系统接管并释放[^2]。 尽管如此,在实际开发中,内存泄漏仍然可能导致以下问题: - 如果程序是长期运行的服务或应用程序,内存泄漏会导致内存占用逐渐增加,最终可能耗尽系统资源。 - 在调试阶段,内存泄漏可能会掩盖其他潜在问题,增加排查难度[^4]。 以下是示例代码,展示程序意外退出时未释放的内存: ```cpp #include <iostream> void allocateMemory() { int* a = new int; // 动态分配内存 *a = 10; throw std::runtime_error("Unexpected error"); // 模拟意外退出 } int main() { try { allocateMemory(); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; } ``` 在这个例子中,函数 `allocateMemory` 使用 `new` 分配了一块内存,但在执行 `throw` 语句时并未释放该内存。即使程序捕获异常并继续执行,这块内存仍然处于未释放状态[^3]。 ### 总结 C++ 程序意外退出时,`new` 分配的内存确实会发生内存泄漏,但从操作系统的角度来看,这些内存会在进程终止后被回收。为了避免潜在问题,建议在程序设计中遵循 RAII(Resource Acquisition Is Initialization)原则,使用智能指针(如 `std::unique_ptr` 或 `std::shared_ptr`)来管理动态分配的内存,从而确保资源能够正确释放。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值