Allen's Blog

View on GitHub
24 April 2024

Smart Pointers

by Allen Sun

1 背景

直接使用C++指针可能会引发下列问题:

  1. 内存泄漏(Memory Leak):不停地手动分配内存,但是从来不回收,系统会因内存耗尽而崩溃。

  2. 悬浮指针(Dangling Pointer):指针指向的内存被回收后,指针的指向仍没有改变。

  3. 野指针(Wild Pointer):指针从未被初始化,从未指向合法的数据。

  4. 数据不一致(Data Inconsistency):内存中的数据没有按一致性次序更新。

为了解决上述问题,C++提出了“用对象的方式管理内存”,模型如下:

template <typename T>
class SmartPointer{
    T* raw_ptr_;
public:
    explicit SmartPointer(T* p = nullptr) : raw_ptr_(p) {}
    ~SmartPointer(){
        /**
         * 智能指针的生存期结束时:
         * 自动调用析构函数释放其所指向的数据对象
         */
        delete raw_ptr_;
    }
    T& operator*(){
        return *raw_ptr_;
    }
};

2 unique_ptr

同一时刻,只能有一个指针指向数据对象。

#include <memory>

void foo(){
    std::unique_ptr<int> p1(new int(38));  // p1指向38
    std::unique_ptr<int> p2;
    p2 = std::move(p1);  // p2指向38,并且,p1指向空
}

3 shared_ptr

同一时刻,可以有多个指针指向数据对象,基于引用计数实现。

#include <memory>

void foo(){
    std::shared_ptr<int> p1(new int(38));
    std::shared_ptr<int> p2;
    p2 = p1;  // 引用计数增加
}

引用计数

使用make_shared构造指针对象

/* 方式一 */
auto* ptr = new DataObject(/* args */);  // 为数据对象分配内存
std::shared_ptr<DataObject> shptr{ptr};  // 为指针对象及控制块分配内存

/* 方式二 */
auto shptr = std::make_shared<DataObject>(/* args */);

4 weak_ptr

主要用于解决shared_ptr在引用计数过程中可能出现的“死锁”问题。

class B;
class A
{
public:
    std::shared_ptr<B> pb_;
};
class B
{
public:
    std::shared_ptr<A> pa_;
};
class B;
class A
{
public:
    std::weak_ptr<B> pb_weak;
};
class B
{
public:
    std::shared_ptr<A> pa_;
};
tags: C++ - Memory-Management - Pointers