智能指针
参考资料:
日期:2022年9月7日
一、什么是智能指针
在 C++ 中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针(smart pointer)。
智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动地销毁动态分配的对象,防止内存泄露。
智能指针的核心实现技术是引用计数,每使用它一次,内部引用计数加 1,每析构一次内部的引用计数减 1,减为 0 时,删除所指向的堆内存。
C++ 中用得最多的是下面三种智能指针(C++11 引入,需要引用头文件 <memory>):
std::shared_ptr:共享的智能指针std::unique_ptr:独占的智能指针std::weak_ptr:弱引用的智能指针,它不共享指针,不能操作资源,是用来监视shared_ptr的
二、独占指针 unique_ptr
其特点是确保仅有一个指针指向堆对象,可以重新分配堆对象,不允许有另外的 unique_ptr 指向同一块内存。
可以声明自定义删除器,即当被删除时,将会调用自定义删除器(删除函数?)来删除对象。
构造方式:
auto ptr = make_unique<type>(); // 推荐
unique_ptr<type>(new type()); // 传统写法
示例代码
void customDeleter(int* ptr) {
std::cout << "Custom deleter is called." << std::endl;
delete ptr;
}
void uF() {
unique_ptr<int> u(new int(2));
cout << *u << endl;
unique_ptr<int> u1 = make_unique<int>(3);
cout << *u1 << endl;
unique_ptr<int[]> arr = make_unique<int[]>(10); // 创建数组,长度为 10
for(int i = 0; i < 10; i++)
arr[i] = i + 1;
for(int i = 0; i < 10; i++)
cout << arr[i] << " ";
cout << endl;
// unique_ptr<int> p = u; // 不允许有另外的 unique_ptr 指向同一块内存
cout << u.get() << endl;
u = make_unique<int>(4); // 允许重新分配, 原先的内存被自动删除回收
cout << u.get() << endl;
unique_ptr<int, decltype(&customDeleter)> u2(new int(5), customDeleter); // 定义自定义删除器
// 使用自定义删除器类创建 unique_ptr
struct CustomDeleter {
void operator()(int* ptr) const {
std::cout << "Custom deleter class is called." << std::endl;
delete ptr;
}
};
std::unique_ptr<int, CustomDeleter> u3(new int(24));
/*
unique_ptr 确保只能有一个指针(一个 unique_ptr)指向一个对象,
当 unique_ptr 被销毁时(这往往发生在重新分配,和离开生存周期时),
它指向的对象也会被自动释放。
并且可以为 unique_ptr 指定自定义删除器,
这样当 unique_ptr 被销毁时,就可以自定义释放内存(或者。。。不释放?)。
*/
}
疑问:
unique_ptr<int*> u1 = make_unique<int*>();
// 如果这样写,会发生啥?
三、共享指针 shared_ptr
为了做出一个像 Java 中的垃圾回收机制,并可以应用于所有资源(heap 内存和系统资源)的系统,C++11 推出了 std::shared_ptr。
使用方式与 unique_ptr 类似:
shared_ptr<int> p(new int(10)); // 等同于
shared_ptr<int> p = shared_ptr<int>(new int(10));
shared_ptr<int> p2 = make_shared<int>(20); // 推荐的方式
直观对比示例:
shared_ptr<int> p(new int(10));
shared_ptr<int> p2 = make_shared<int>(20);
p2 = p; // 没毛病
cout << p.use_count() << endl; // 输出 2
unique_ptr<int> u(new int(2));
unique_ptr<int> u1(new int(1));
u = u1; // 有毛病
- 使用
use_count()可以查看当前的引用计数,比如上面的就输出2 - 并且,这是互相的:不仅是
p的引用计数是 2,p2的引用计数也是 2 unique()方法可以直接判断当前共享指针对象是否唯一
2025年4月10日补充
判断是否为空的方式
shared_ptr<int> sp;
if (sp) {
cout << "不为空: " << *sp << endl;
} else {
cout << "为空" << endl;
}

浙公网安备 33010602011771号