智能指针

参考资料:

日期: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

参考文章:shared_ptr_shared ptr-CSDN博客

为了做出一个像 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;
}
posted @ 2025-04-10 10:44  yueyingyifeng  阅读(20)  评论(0)    收藏  举报