智能指针概念、方法总结


前言

本文对C++的shared_ptr,unique_ptr,weak_ptr智能指针的概念及目的,应用场景,常见方法进行总结;

一、智能指针概述

智能指针是C++11中的新标准特性,是对new/delete分配释放内存进一步封装的一个类,一个智能指针对象,除了指向动态内存地址,还封装了计数器(shared_ptr),可以自动的释放动态资源,避免资源泄漏及悬空指针问题;

二、三种智能指针应用场景及常见方法比较

1.shared_ptr

场景:当需要多个指针访问同一个共享资源股时,可以使用shared_ptr;
常见方法示例:

#include <iostream>
#include <memory>

class SharedObject {
public:
    SharedObject() { std::cout << "SharedObject constructed\n"; }
    ~SharedObject() { std::cout << "SharedObject destructed\n"; }
    void doSomething() { std::cout << "Doing something\n"; }
};

int main() {
    // 使用 make_shared 创建 shared_ptr
    std::shared_ptr<SharedObject> sharedPtr1 = std::make_shared<SharedObject>();

    // 使用 new 创建 shared_ptr
    std::shared_ptr<SharedObject> sharedPtr2(new SharedObject());

    // get() 方法
    SharedObject* rawPtr = sharedPtr1.get();
    rawPtr->doSomething();

    // use_count() 方法
    std::cout << "Reference count: " << sharedPtr1.use_count() << std::endl;

    // reset() 方法
    sharedPtr2.reset(new SharedObject()); // 替换为新的 SharedObject
    sharedPtr2.reset(); // 释放 SharedObject,sharedPtr2 变为空

    // swap() 方法
    std::shared_ptr<SharedObject> sharedPtr3;
    sharedPtr1.swap(sharedPtr3); // 交换 sharedPtr1 和 sharedPtr3

    // operator* 和 operator-> 
    sharedPtr1->doSomething();

    // operator=
    sharedPtr3 = sharedPtr1; // 增加引用计数

    return 0;
}

补充说明:

  1. make_shared:创建一个 shared_ptr 实例,并自动管理对象的生命周期。 get():返回一个指向管理对象的原始指针。
    use_count():返回引用计数,即有多少个 shared_ptr 和 weak_ptr 共享同一个对象。 reset():重置
    shared_ptr,释放当前管理的对象,并可选地构造一个新的对象。 swap():交换两个 shared_ptr 所管理的对象。
    operator* 和 operator->:允许通过解引用和成员访问运算符来访问 shared_ptr 管理的对象。
    operator=:赋值运算符,通过移动语义转移 shared_ptr 的所有权。

2.unique_ptr

场景:当需要指针访问独占的访问某个资源时,可以使用unique_ptr;
常见方法示例:

#include <memory>
#include <iostream>

class MyClass {
public:
    MyClass() { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destructed\n"; }
    void doSomething() { std::cout << "Doing something\n"; }
};

int main() {
    // 构造函数
    std::unique_ptr<MyClass> uniquePtr1(new MyClass()); // 默认构造函数
    std::unique_ptr<MyClass> uniquePtr2 = std::make_unique<MyClass>(); // 使用 make_unique 创建

    // get() 方法
    MyClass* rawPtr = uniquePtr1.get(); // 获取原始指针
    rawPtr->doSomething();

    // reset() 方法
    uniquePtr1.reset(new MyClass()); // 释放旧对象,构造新对象
    uniquePtr1.reset(); // 释放对象,unique_ptr 变为空

    // release() 方法
    MyClass* releasedPtr = uniquePtr2.release(); // 释放对象,返回原始指针,unique_ptr 变为空
    delete releasedPtr; // 需要手动删除释放的指针

    // swap() 方法
    std::unique_ptr<MyClass> uniquePtr3(new MyClass());
    uniquePtr1.swap(uniquePtr3); // 交换 uniquePtr1 和 uniquePtr3 所管理的对象

    // operator* 和 operator->
    uniquePtr2->doSomething(); // 访问 MyClass 的成员函数

    // operator=(赋值运算符)
    std::unique_ptr<MyClass> uniquePtr4;
    uniquePtr4 = std::move(uniquePtr2); // 转移所有权,uniquePtr2 变为空

    // 比较运算符
    std::unique_ptr<MyClass> uniquePtr5(new MyClass());
    if (uniquePtr5 == nullptr) {
        std::cout << "uniquePtr5 is empty\n";
    }
    if (uniquePtr5 != nullptr) {
        std::cout << "uniquePtr5 is not empty\n";
    }

    // 检查空值
    if (!uniquePtr5) {
        std::cout << "uniquePtr5 is empty\n";
    }

    return 0;
}

补充说明:

  1. 构造函数:使用 new 运算符或 std::make_unique 创建 unique_ptr。
    get():返回一个指向管理对象的原始指针。 reset():重置 unique_ptr,释放当前管理的对象,并可选地构造一个新的对 象。
    release():释放 unique_ptr 管理的对象,返回原始指针,并使 unique_ptr 变为空。释放的指针需要手动删除。
    swap():交换两个 unique_ptr 所管理的对象。 operator* 和
    operator->:允许通过解引用和成员访问运算符来访问 unique_ptr 管理的对象。
    operator=(赋值运算符):通过移动语义转移 unique_ptr 的所有权。 比较运算符:可以检查 unique_ptr
    是否为空。 空值检查:直接使用 if (!uniquePtr) 来检查 unique_ptr 是否为空。

3.weak_ptr

场景:但需要不增加引用计数的同时,范围共享资源时,可以使用weak_ptr
常见方法:

#include <iostream>
#include <memory>

class WeakObject {
public:
    WeakObject() { std::cout << "WeakObject constructed\n"; }
    ~WeakObject() { std::cout << "WeakObject destructed\n"; }
    void doSomething() { std::cout << "Doing something\n"; }
};

int main() {
    // 创建 shared_ptr
    std::shared_ptr<WeakObject> sharedPtr1 = std::make_shared<WeakObject>();

    // 创建 weak_ptr
    std::weak_ptr<WeakObject> weakPtr1(sharedPtr1);

    // 使用 weak_ptr 的 lock() 方法获取 shared_ptr
    std::shared_ptr<WeakObject> lockedPtr = weakPtr1.lock();
    if (lockedPtr) {
        lockedPtr->doSomething();
    }

    // 检查 weak_ptr 是否有效
    if (weakPtr1.expired()) {
        std::cout << "WeakObject has been deleted\n";
    }

    // reset() 方法
    weakPtr1.reset(); // 重置 weak_ptr

    // swap() 方法
    std::weak_ptr<WeakObject> weakPtr2;
    weakPtr1.swap(weakPtr2); // 交换 weakPtr1 和 weakPtr2

    // 使用 weak_ptr 的 use_count() 方法
    std::cout << "Weak reference count: " << weakPtr1.use_count() << std::endl;

    return 0;
}

补充说明:

  1. lock():获取一个 shared_ptr,如果 weak_ptr 已经失效,则返回一个空的 shared_ptr。
    expired():检查 weak_ptr 是否有效,即它所指向的对象是否已经被删除。 reset():重置
    weak_ptr,使其不再指向任何对象。 swap():交换两个 weak_ptr。 use_count():返回引用计数,即有多少个
    shared_ptr 共享同一个对象(注意:weak_ptr 本身不增加引用计数)。

总结

以上就是今天要分享的内容,下表是对三种指针指针的对比,至于更多的使用细节可以参考其他优秀博客。

特性/方法std::unique_ptrstd::shared_ptrstd::weak_ptr
所有权独占所有权共享所有权弱引用,不拥有所有权
构造newstd::make_uniquenewstd::make_sharedshared_ptr 构造
析构自动释放所管理的对象自动释放所管理的对象(当引用计数为0时)不释放对象
复制不可复制(移动语义)复制时增加引用计数不可复制(移动语义)
移动可移动(转移所有权)可移动(转移所有权)可移动(转移弱引用)
空值检查使用 == nullptr使用 == nullptr使用 expired()use_count() == 0
获取原始指针get()get()lock().get()
重置reset()reset()reset()
交换swap()swap()swap()
引用计数有(通过 use_count() 访问)无(通过 use_count() 访问共享计数)
常用方法get(), release(), reset(), swap()get(), reset(), swap(), use_count()lock(), reset(), swap(), use_count()
适用场景需要独占访问资源时需要多个所有者共享资源时需要避免循环引用或延迟获取资源时
  • 26
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小凡下方了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值