- 智能指针确保资源正确释放的原理
std::unique_ptr
:
std::unique_ptr
采用了RAII(Resource Acquisition Is Initialization)机制。当std::unique_ptr
对象在栈上创建时,它获取资源(例如通过new
操作符分配内存)。当std::unique_ptr
对象离开其作用域(无论是正常结束还是因为异常),它的析构函数会被自动调用。在析构函数中,std::unique_ptr
会释放其所管理的资源(例如调用delete
操作符释放内存)。
std::shared_ptr
:
std::shared_ptr
同样基于RAII机制。它通过引用计数来管理资源。当std::shared_ptr
对象创建时,引用计数初始化为1。每次有新的std::shared_ptr
对象指向相同的资源(例如通过拷贝构造函数或赋值操作符),引用计数增加。当std::shared_ptr
对象离开其作用域(正常或因异常),引用计数减1。当引用计数变为0时,所管理的资源会被释放。
- 举例说明
#include <iostream>
#include <memory>
void func() {
std::unique_ptr<int> ptr(new int(10));
std::cout << "Before throwing exception, value: " << *ptr << std::endl;
throw std::runtime_error("Exception thrown");
std::cout << "This line won't be reached" << std::endl;
}
int main() {
try {
func();
} catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
- 在上述代码中,
func
函数创建了一个std::unique_ptr<int>
对象ptr
并分配了一个int
类型的内存。然后抛出一个异常。即使异常发生,std::unique_ptr
的析构函数会确保分配的int
内存被正确释放。
std::shared_ptr
示例:
#include <iostream>
#include <memory>
void func() {
std::shared_ptr<int> ptr(new int(20));
std::cout << "Before throwing exception, value: " << *ptr << std::endl;
std::shared_ptr<int> ptr2 = ptr;
throw std::runtime_error("Exception thrown");
std::cout << "This line won't be reached" << std::endl;
}
int main() {
try {
func();
} catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
- 在这个代码中,
func
函数创建了一个std::shared_ptr<int>
对象ptr
并分配了一个int
类型的内存。然后创建了另一个std::shared_ptr<int>
对象ptr2
指向相同的内存,引用计数变为2。当抛出异常时,ptr
和ptr2
离开作用域,引用计数减1变为0,所管理的int
内存会被正确释放。