首页 > 编程笔记 > C++笔记 阅读:3

C++ std::shared_ptr智能指针详解(附带实例)

C++11 引入了 3 种智能指针,它们是 std::shared_ptr、std::unique_ptr 和 std::weak_ptr。这些智能指针提供了更安全和方便的内存管理方式,主要用于管理动态分配的对象,主要通过利用对象的析构操作来自动释放内存,以此来提高内存的安全性。

这些智能指针提供了比传统指针更安全和更方便的内存管理方式。它们采用了 RAII(Resource Acquisition Is Initialization,资源获取就是初始化)原则,可以在对象超出作用域时自动释放资源,不再需要手动进行内存的分配和释放操作,从而减少内存泄漏和悬空指针的风险。此外,它们还提供了更多功能,如自定义删除器、自定义析构函数等,以更好地满足不同的需求。

C++ std::shared_ptr的用法

std::shared_ptr 是 C++11 中的智能指针,用于管理动态分配的对象资源,以自动进行资源释放。它是一个引用计数智能指针,可以让多个 shared_ptr 对象共享同一个资源,在最后一个 shared_ptr 被销毁时释放资源。

引用计数是一个用于追踪有多少个 std::shared_ptr 共享同一个对象的整数值。它用于确定何时销毁动态分配的对象。

每次创建一个新的std::shared_ptr指向同一个对象时,引用计数会递增。当std::shared_ptr被销毁时,引用计数会递减。只有当引用计数变为0时,std::shared_ptr才会删除动态分配的对象并释放其占用的内存。

引用计数的基本原理是,每个 std::shared_ptr 对象都有一个指向一个控制块的指针。控制块是一个结构体,包含了引用计数和指向动态分配对象的指针。在每次创建或销毁 std::shared_ptr 对象时,引用计数会相应地进行递增或递减。

当引用计数减少到 0 时,std::shared_ptr 会调用其析构函数来销毁动态分配的对象,并释放控制块的内存。这确保了动态分配对象的生存期与所有引用它的 std::shared_ptr 对象的生存期一致。

引用计数的使用使多个 std::shared_ptr 对象可以共享同一对象的所有权,而不会造成资源的重复释放或悬空指针的情况。它提供了一种方便和安全的资源管理方式,能够自动进行内存释放。

需要注意的是,在使用 std::shared_ptr 进行循环引用时,可能会出现资源泄漏的问题。为了避免循环引用造成的资源无法释放的情况,需要使用 std::weak_ptr来 打破循环引用。

使用 std::shared_ptr 需要包含头文件 <memory>。下面是一个使用 shared_ptr 的示例,代码如下:
#include <memory>
#include <iostream>

class MyClass
{
public:
    MyClass()
    {
        std::cout << "MyClass Constructor" << std::endl;
    }
    ~MyClass()
    {
        std::cout << "MyClass Destructor" << std::endl;
    }
    void doSomething()
    {
        std::cout << "Doing something..." << std::endl;
    }
};

int main()
{
    std::shared_ptr<MyClass> ptr1(new MyClass());    //创建一个新的 MyClass 对象
    //复制 ptr1,使 ptr2 和 ptr1 共享同一资源
    std::shared_ptr<MyClass> ptr2 = ptr1;
    ptr1->doSomething();      //可以通过 ptr1 访问资源的成员函数
    ptr2->doSomething();      //ptr1 和 ptr2 都指向同一资源
    return 0;
} //离开作用域时,ptr1 和 ptr2 都被销毁,资源自动释放
执行结果为:

MyClass Constructor
Doing something...
Doing something...
MyClass Destructor

在上述示例中,通过 std::shared_ptr 来管理 MyClass 对象的资源。在创建 shared_ptr 时,可以通过传入指向动态分配的对象的裸指针来初始化 shared_ptr。在使用 shared_ptr 时,可以像使用裸指针一样访问对象的成员函数和数据成员。

在示例中,ptr1 和 ptr2 共享同一个 MyClass 对象。当 ptr1 和 ptr2 超出作用域时,它们都被销毁,MyClass 对象的析构函数会被调用,从而释放资源。

使用 std::shared_ptr 可以避免手动管理动态分配资源的麻烦,实现了自动化的资源管理,避免了内存泄漏和悬空指针的问题。

C++ std::make_shared()的用法

C++ 提供了一个工厂函数模板 std::make_shared(),可以很方便地创建 std::shared_ptr 指针并将它初始化为指向动态分配的对象。

std::make_shared() 可以简化创建 shared_ptr 的过程,并提供了更高的性能和安全性:
下面是一个使用 std::make_shared 的示例,代码如下:
#include <memory>
#include <iostream>

class MyClass
{
public:
    MyClass(int value) : m_value(value)
    {
        std::cout << "MyClass Constructor, value: " << m_value << std::endl;
    }
    ~MyClass()
    {
        std::cout << "MyClass Destructor, value: " << m_value << std::endl;
    }
    void doSomething()
    {
        std::cout << "Doing something with value: " << m_value << std::endl;
    }
private:
    int m_value;
};

int main()
{
    //使用 std::make_shared<>() 构造对象
    std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(42);
    ptr->doSomething();
    return 0;
} //当离开作用域时,ptr 被销毁,MyClass 对象的析构函数会被调用,从而释放资源
执行结果为:

MyClass Constructor, value: 42
Doing something with value: 42
MyClass Destructor, value: 42

在示例中,使用 std::make_shared 创建了一个指向 MyClass 对象的 std::shared_ptr 指针 ptr,同时将 MyClass 对象的值初始化为 42。当 ptr 超出作用域时,ptr 被销毁,MyClass 对象的析构函数会被调用,从而释放资源。

相关文章