前端学C++

135 阅读1分钟

这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

聊聊智能指针

Effective Modern C++中这样评价指针:

  • 裸指针声明并不确定其指向的是单个对象还是数组。
  • 裸指针不声明其指向对象是否需要及何时析构
  • 没有方法能够检测出一个指针是否空悬,即某个对象已经析构了,有指针依然指向它,产生空指针。

因而引入了智能指针:std::auto_ptr,std::unique_ptr,std::shared_ptr,std::weak_ptr 。这四种智能指针中,std::auto_ptr可以看作废弃的特性,只有在C++98编译器下才会使用它。聊聊其他三种智能指针。

std::unique_ptr

std::unique_ptr是最常用的智能指针,使用普通指针时,要删除:

{
    int* p = new int(100);
    // ...
    delete p;  // 要记得释放内存
}

使用智能指针时:


std::unique_ptr<int> uptr = std::make_unique<int>(200);
\\  指向数组的形式
{
    std::unique_ptr<int[]> uptr = std::make_unique<int[]>(10);
    for (int i = 0; i < 10; i++) {
        uptr[i] = i * i;
    }   
    for (int i = 0; i < 10; i++) {
        std::cout << uptr[i] << std::endl;
    }   
}

std::unique_ptr的默认析构方法是Delete,也可以用如下方法自定义析构:

{
    struct FileCloser {
        void operator()(FILE* fp) const {
            if (fp != nullptr) {
                fclose(fp);
            }
        }   
    };  
    std::unique_ptr<FILE, FileCloser> uptr(fopen("test_file.txt", "w"));
}

std::shared_ptr

std::shared_ptr对资源进行计数,为0时释放资源,其初始化与复制赋值如下:

std::shared_ptr<int> sptr = std::make_shared<int>(200);

std::shared_ptr<int> sptr1 = sptr;

assert(sptr.use_count() == 2);   // sptr 和 sptr1 共享资源,引用计数为 2

std::weak_ptr

来个例子:

void Observe(std::weak_ptr<int> wptr) {
    if (auto sptr = wptr.lock()) {
        std::cout << "value: " << *sptr << std::endl;
    } else {
        std::cout << "wptr lock fail" << std::endl;
    }
}

std::weak_ptr<int> wptr;
{
    auto sptr = std::make_shared<int>(111);
    wptr = sptr;
    Observe(wptr);  // sptr 指向的资源没被释放,wptr 可以成功提升为 shared_ptr
}
Observe(wptr);  // sptr 指向的资源已被释放,wptr 无法提升为 shared_ptr

可以看到std::weak_ptrstd::shared_ptr一起使用,std::weak_ptr不参与std::shared_ptr的计数操作,但能检测出其是否空悬,上面这个例子当shared_ptr 管理的资源被释放时,weak_ptr 会自动变成 nullptr